├── .gitignore ├── FBConnect ├── FBConnect.h ├── FBDialog.bundle │ └── images │ │ ├── close.png │ │ ├── close@2x.png │ │ └── fbicon.png ├── FBDialog.h ├── FBDialog.m ├── FBLoginDialog.h ├── FBLoginDialog.m ├── FBRequest.h ├── FBRequest.m ├── Facebook.h ├── Facebook.m ├── JSON │ ├── JSON.h │ ├── NSObject+SBJSON.h │ ├── NSObject+SBJSON.m │ ├── NSString+SBJSON.h │ ├── NSString+SBJSON.m │ ├── SBJSON.h │ ├── SBJSON.m │ ├── SBJsonBase.h │ ├── SBJsonBase.m │ ├── SBJsonParser.h │ ├── SBJsonParser.m │ ├── SBJsonWriter.h │ └── SBJsonWriter.m └── README.mdown ├── FacebookLikeView ├── Classes │ ├── Facebook+ForceDialog.m │ ├── FacebookLikeView.h │ └── FacebookLikeView.m └── Resources │ └── FacebookLikeView.html ├── FacebookLikeViewDemo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── FacebookLikeViewDemo ├── Default-568h@2x.png ├── FacebookLikeViewDemo-Info.plist ├── FacebookLikeViewDemo-Prefix.pch ├── FacebookLikeViewDemoAppDelegate.h ├── FacebookLikeViewDemoAppDelegate.m ├── FacebookLikeViewDemoViewController.h ├── FacebookLikeViewDemoViewController.m ├── LikeButtonDemo-Info.plist ├── LikeButtonDemo-Prefix.pch ├── en.lproj │ ├── FacebookLikeViewDemoViewController.xib │ ├── InfoPlist.strings │ └── MainWindow.xib └── main.m ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/* 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | -------------------------------------------------------------------------------- /FBConnect/FBConnect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #include "Facebook.h" 19 | #include "FBDialog.h" 20 | #include "FBLoginDialog.h" 21 | #include "FBRequest.h" 22 | #include "SBJSON.h" -------------------------------------------------------------------------------- /FBConnect/FBDialog.bundle/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/FacebookLikeView/da914d9c9ef0306b2a2a888e3b2d71e26f22dd3b/FBConnect/FBDialog.bundle/images/close.png -------------------------------------------------------------------------------- /FBConnect/FBDialog.bundle/images/close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/FacebookLikeView/da914d9c9ef0306b2a2a888e3b2d71e26f22dd3b/FBConnect/FBDialog.bundle/images/close@2x.png -------------------------------------------------------------------------------- /FBConnect/FBDialog.bundle/images/fbicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/FacebookLikeView/da914d9c9ef0306b2a2a888e3b2d71e26f22dd3b/FBConnect/FBDialog.bundle/images/fbicon.png -------------------------------------------------------------------------------- /FBConnect/FBDialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | 20 | @protocol FBDialogDelegate; 21 | 22 | /** 23 | * Do not use this interface directly, instead, use dialog in Facebook.h 24 | * 25 | * Facebook dialog interface for start the facebook webView UIServer Dialog. 26 | */ 27 | 28 | @interface FBDialog : UIView { 29 | id _delegate; 30 | NSMutableDictionary *_params; 31 | NSString * _serverURL; 32 | NSURL* _loadingURL; 33 | UIWebView* _webView; 34 | UIActivityIndicatorView* _spinner; 35 | UIButton* _closeButton; 36 | UIInterfaceOrientation _orientation; 37 | BOOL _showingKeyboard; 38 | 39 | // Ensures that UI elements behind the dialog are disabled. 40 | UIView* _modalBackgroundView; 41 | } 42 | 43 | /** 44 | * The delegate. 45 | */ 46 | @property(nonatomic,assign) id delegate; 47 | 48 | /** 49 | * The parameters. 50 | */ 51 | @property(nonatomic, retain) NSMutableDictionary* params; 52 | 53 | - (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle; 54 | 55 | - (id)initWithURL: (NSString *) loadingURL 56 | params: (NSMutableDictionary *) params 57 | delegate: (id ) delegate; 58 | 59 | /** 60 | * Displays the view with an animation. 61 | * 62 | * The view will be added to the top of the current key window. 63 | */ 64 | - (void)show; 65 | 66 | /** 67 | * Displays the first page of the dialog. 68 | * 69 | * Do not ever call this directly. It is intended to be overriden by subclasses. 70 | */ 71 | - (void)load; 72 | 73 | /** 74 | * Displays a URL in the dialog. 75 | */ 76 | - (void)loadURL:(NSString*)url 77 | get:(NSDictionary*)getParams; 78 | 79 | /** 80 | * Hides the view and notifies delegates of success or cancellation. 81 | */ 82 | - (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated; 83 | 84 | /** 85 | * Hides the view and notifies delegates of an error. 86 | */ 87 | - (void)dismissWithError:(NSError*)error animated:(BOOL)animated; 88 | 89 | /** 90 | * Subclasses may override to perform actions just prior to showing the dialog. 91 | */ 92 | - (void)dialogWillAppear; 93 | 94 | /** 95 | * Subclasses may override to perform actions just after the dialog is hidden. 96 | */ 97 | - (void)dialogWillDisappear; 98 | 99 | /** 100 | * Subclasses should override to process data returned from the server in a 'fbconnect' url. 101 | * 102 | * Implementations must call dismissWithSuccess:YES at some point to hide the dialog. 103 | */ 104 | - (void)dialogDidSucceed:(NSURL *)url; 105 | 106 | /** 107 | * Subclasses should override to process data returned from the server in a 'fbconnect' url. 108 | * 109 | * Implementations must call dismissWithSuccess:YES at some point to hide the dialog. 110 | */ 111 | - (void)dialogDidCancel:(NSURL *)url; 112 | @end 113 | 114 | /////////////////////////////////////////////////////////////////////////////////////////////////// 115 | 116 | /* 117 | *Your application should implement this delegate 118 | */ 119 | @protocol FBDialogDelegate 120 | 121 | @optional 122 | 123 | /** 124 | * Called when the dialog succeeds and is about to be dismissed. 125 | */ 126 | - (void)dialogDidComplete:(FBDialog *)dialog; 127 | 128 | /** 129 | * Called when the dialog succeeds with a returning url. 130 | */ 131 | - (void)dialogCompleteWithUrl:(NSURL *)url; 132 | 133 | /** 134 | * Called when the dialog get canceled by the user. 135 | */ 136 | - (void)dialogDidNotCompleteWithUrl:(NSURL *)url; 137 | 138 | /** 139 | * Called when the dialog is cancelled and is about to be dismissed. 140 | */ 141 | - (void)dialogDidNotComplete:(FBDialog *)dialog; 142 | 143 | /** 144 | * Called when dialog failed to load due to an error. 145 | */ 146 | - (void)dialog:(FBDialog*)dialog didFailWithError:(NSError *)error; 147 | 148 | /** 149 | * Asks if a link touched by a user should be opened in an external browser. 150 | * 151 | * If a user touches a link, the default behavior is to open the link in the Safari browser, 152 | * which will cause your app to quit. You may want to prevent this from happening, open the link 153 | * in your own internal browser, or perhaps warn the user that they are about to leave your app. 154 | * If so, implement this method on your delegate and return NO. If you warn the user, you 155 | * should hold onto the URL and once you have received their acknowledgement open the URL yourself 156 | * using [[UIApplication sharedApplication] openURL:]. 157 | */ 158 | - (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL *)url; 159 | 160 | @end 161 | -------------------------------------------------------------------------------- /FBConnect/FBDialog.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #import "FBDialog.h" 19 | #import "Facebook.h" 20 | 21 | /////////////////////////////////////////////////////////////////////////////////////////////////// 22 | // global 23 | 24 | static CGFloat kBorderGray[4] = {0.3, 0.3, 0.3, 0.8}; 25 | static CGFloat kBorderBlack[4] = {0.3, 0.3, 0.3, 1}; 26 | 27 | static CGFloat kTransitionDuration = 0.3; 28 | 29 | static CGFloat kPadding = 0; 30 | static CGFloat kBorderWidth = 10; 31 | 32 | /////////////////////////////////////////////////////////////////////////////////////////////////// 33 | 34 | static BOOL FBIsDeviceIPad() { 35 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200 36 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 37 | return YES; 38 | } 39 | #endif 40 | return NO; 41 | } 42 | 43 | /////////////////////////////////////////////////////////////////////////////////////////////////// 44 | 45 | @implementation FBDialog 46 | 47 | @synthesize delegate = _delegate, 48 | params = _params; 49 | 50 | /////////////////////////////////////////////////////////////////////////////////////////////////// 51 | // private 52 | 53 | - (void)addRoundedRectToPath:(CGContextRef)context rect:(CGRect)rect radius:(float)radius { 54 | CGContextBeginPath(context); 55 | CGContextSaveGState(context); 56 | 57 | if (radius == 0) { 58 | CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect)); 59 | CGContextAddRect(context, rect); 60 | } else { 61 | rect = CGRectOffset(CGRectInset(rect, 0.5, 0.5), 0.5, 0.5); 62 | CGContextTranslateCTM(context, CGRectGetMinX(rect)-0.5, CGRectGetMinY(rect)-0.5); 63 | CGContextScaleCTM(context, radius, radius); 64 | float fw = CGRectGetWidth(rect) / radius; 65 | float fh = CGRectGetHeight(rect) / radius; 66 | 67 | CGContextMoveToPoint(context, fw, fh/2); 68 | CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); 69 | CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); 70 | CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); 71 | CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); 72 | } 73 | 74 | CGContextClosePath(context); 75 | CGContextRestoreGState(context); 76 | } 77 | 78 | - (void)drawRect:(CGRect)rect fill:(const CGFloat*)fillColors radius:(CGFloat)radius { 79 | CGContextRef context = UIGraphicsGetCurrentContext(); 80 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); 81 | 82 | if (fillColors) { 83 | CGContextSaveGState(context); 84 | CGContextSetFillColor(context, fillColors); 85 | if (radius) { 86 | [self addRoundedRectToPath:context rect:rect radius:radius]; 87 | CGContextFillPath(context); 88 | } else { 89 | CGContextFillRect(context, rect); 90 | } 91 | CGContextRestoreGState(context); 92 | } 93 | 94 | CGColorSpaceRelease(space); 95 | } 96 | 97 | - (void)strokeLines:(CGRect)rect stroke:(const CGFloat*)strokeColor { 98 | CGContextRef context = UIGraphicsGetCurrentContext(); 99 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); 100 | 101 | CGContextSaveGState(context); 102 | CGContextSetStrokeColorSpace(context, space); 103 | CGContextSetStrokeColor(context, strokeColor); 104 | CGContextSetLineWidth(context, 1.0); 105 | 106 | { 107 | CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y-0.5}, 108 | {rect.origin.x+rect.size.width, rect.origin.y-0.5}}; 109 | CGContextStrokeLineSegments(context, points, 2); 110 | } 111 | { 112 | CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5}, 113 | {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}}; 114 | CGContextStrokeLineSegments(context, points, 2); 115 | } 116 | { 117 | CGPoint points[] = {{rect.origin.x+rect.size.width-0.5, rect.origin.y}, 118 | {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}}; 119 | CGContextStrokeLineSegments(context, points, 2); 120 | } 121 | { 122 | CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y}, 123 | {rect.origin.x+0.5, rect.origin.y+rect.size.height}}; 124 | CGContextStrokeLineSegments(context, points, 2); 125 | } 126 | 127 | CGContextRestoreGState(context); 128 | 129 | CGColorSpaceRelease(space); 130 | } 131 | 132 | - (BOOL)shouldRotateToOrientation:(UIInterfaceOrientation)orientation { 133 | if (orientation == _orientation) { 134 | return NO; 135 | } else { 136 | return orientation == UIInterfaceOrientationPortrait 137 | || orientation == UIInterfaceOrientationPortraitUpsideDown 138 | || orientation == UIInterfaceOrientationLandscapeLeft 139 | || orientation == UIInterfaceOrientationLandscapeRight; 140 | } 141 | } 142 | 143 | - (CGAffineTransform)transformForOrientation { 144 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 145 | if (orientation == UIInterfaceOrientationLandscapeLeft) { 146 | return CGAffineTransformMakeRotation(M_PI*1.5); 147 | } else if (orientation == UIInterfaceOrientationLandscapeRight) { 148 | return CGAffineTransformMakeRotation(M_PI/2); 149 | } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { 150 | return CGAffineTransformMakeRotation(-M_PI); 151 | } else { 152 | return CGAffineTransformIdentity; 153 | } 154 | } 155 | 156 | - (void)sizeToFitOrientation:(BOOL)transform { 157 | if (transform) { 158 | self.transform = CGAffineTransformIdentity; 159 | } 160 | 161 | CGRect frame = [UIScreen mainScreen].applicationFrame; 162 | CGPoint center = CGPointMake( 163 | frame.origin.x + ceil(frame.size.width/2), 164 | frame.origin.y + ceil(frame.size.height/2)); 165 | 166 | CGFloat scale_factor = 1.0f; 167 | if (FBIsDeviceIPad()) { 168 | // On the iPad the dialog's dimensions should only be 60% of the screen's 169 | scale_factor = 0.6f; 170 | } 171 | 172 | CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2; 173 | CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2; 174 | 175 | _orientation = [UIApplication sharedApplication].statusBarOrientation; 176 | if (UIInterfaceOrientationIsLandscape(_orientation)) { 177 | self.frame = CGRectMake(kPadding, kPadding, height, width); 178 | } else { 179 | self.frame = CGRectMake(kPadding, kPadding, width, height); 180 | } 181 | self.center = center; 182 | 183 | if (transform) { 184 | self.transform = [self transformForOrientation]; 185 | } 186 | } 187 | 188 | - (void)updateWebOrientation { 189 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 190 | if (UIInterfaceOrientationIsLandscape(orientation)) { 191 | [_webView stringByEvaluatingJavaScriptFromString: 192 | @"document.body.setAttribute('orientation', 90);"]; 193 | } else { 194 | [_webView stringByEvaluatingJavaScriptFromString: 195 | @"document.body.removeAttribute('orientation');"]; 196 | } 197 | } 198 | 199 | - (void)bounce1AnimationStopped { 200 | [UIView beginAnimations:nil context:nil]; 201 | [UIView setAnimationDuration:kTransitionDuration/2]; 202 | [UIView setAnimationDelegate:self]; 203 | [UIView setAnimationDidStopSelector:@selector(bounce2AnimationStopped)]; 204 | self.transform = CGAffineTransformScale([self transformForOrientation], 0.9, 0.9); 205 | [UIView commitAnimations]; 206 | } 207 | 208 | - (void)bounce2AnimationStopped { 209 | [UIView beginAnimations:nil context:nil]; 210 | [UIView setAnimationDuration:kTransitionDuration/2]; 211 | self.transform = [self transformForOrientation]; 212 | [UIView commitAnimations]; 213 | } 214 | 215 | - (NSURL*)generateURL:(NSString*)baseURL params:(NSDictionary*)params { 216 | if (params) { 217 | NSMutableArray* pairs = [NSMutableArray array]; 218 | for (NSString* key in params.keyEnumerator) { 219 | NSString* value = [params objectForKey:key]; 220 | NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes( 221 | NULL, /* allocator */ 222 | (CFStringRef)value, 223 | NULL, /* charactersToLeaveUnescaped */ 224 | (CFStringRef)@"!*'();:@&=+$,/?%#[]", 225 | kCFStringEncodingUTF8); 226 | 227 | [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, escaped_value]]; 228 | [escaped_value release]; 229 | } 230 | 231 | NSString* query = [pairs componentsJoinedByString:@"&"]; 232 | NSString* url = [NSString stringWithFormat:@"%@?%@", baseURL, query]; 233 | return [NSURL URLWithString:url]; 234 | } else { 235 | return [NSURL URLWithString:baseURL]; 236 | } 237 | } 238 | 239 | - (void)addObservers { 240 | [[NSNotificationCenter defaultCenter] addObserver:self 241 | selector:@selector(deviceOrientationDidChange:) 242 | name:@"UIDeviceOrientationDidChangeNotification" object:nil]; 243 | [[NSNotificationCenter defaultCenter] addObserver:self 244 | selector:@selector(keyboardWillShow:) name:@"UIKeyboardWillShowNotification" object:nil]; 245 | [[NSNotificationCenter defaultCenter] addObserver:self 246 | selector:@selector(keyboardWillHide:) name:@"UIKeyboardWillHideNotification" object:nil]; 247 | } 248 | 249 | - (void)removeObservers { 250 | [[NSNotificationCenter defaultCenter] removeObserver:self 251 | name:@"UIDeviceOrientationDidChangeNotification" object:nil]; 252 | [[NSNotificationCenter defaultCenter] removeObserver:self 253 | name:@"UIKeyboardWillShowNotification" object:nil]; 254 | [[NSNotificationCenter defaultCenter] removeObserver:self 255 | name:@"UIKeyboardWillHideNotification" object:nil]; 256 | } 257 | 258 | - (void)postDismissCleanup { 259 | [self removeObservers]; 260 | [self removeFromSuperview]; 261 | [_modalBackgroundView removeFromSuperview]; 262 | } 263 | 264 | - (void)dismiss:(BOOL)animated { 265 | [self dialogWillDisappear]; 266 | 267 | [_loadingURL release]; 268 | _loadingURL = nil; 269 | 270 | if (animated) { 271 | [UIView beginAnimations:nil context:nil]; 272 | [UIView setAnimationDuration:kTransitionDuration]; 273 | [UIView setAnimationDelegate:self]; 274 | [UIView setAnimationDidStopSelector:@selector(postDismissCleanup)]; 275 | self.alpha = 0; 276 | [UIView commitAnimations]; 277 | } else { 278 | [self postDismissCleanup]; 279 | } 280 | } 281 | 282 | - (void)cancel { 283 | [self dialogDidCancel:nil]; 284 | } 285 | 286 | /////////////////////////////////////////////////////////////////////////////////////////////////// 287 | // NSObject 288 | 289 | - (id)init { 290 | if ((self = [super initWithFrame:CGRectZero])) { 291 | _delegate = nil; 292 | _loadingURL = nil; 293 | _showingKeyboard = NO; 294 | 295 | self.backgroundColor = [UIColor clearColor]; 296 | self.autoresizesSubviews = YES; 297 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 298 | self.contentMode = UIViewContentModeRedraw; 299 | 300 | _webView = [[UIWebView alloc] initWithFrame:CGRectMake(kPadding, kPadding, 480, 480)]; 301 | _webView.delegate = self; 302 | _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 303 | [self addSubview:_webView]; 304 | 305 | UIImage* closeImage = [UIImage imageNamed:@"FBDialog.bundle/images/close.png"]; 306 | 307 | UIColor* color = [UIColor colorWithRed:167.0/255 green:184.0/255 blue:216.0/255 alpha:1]; 308 | _closeButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; 309 | [_closeButton setImage:closeImage forState:UIControlStateNormal]; 310 | [_closeButton setTitleColor:color forState:UIControlStateNormal]; 311 | [_closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; 312 | [_closeButton addTarget:self action:@selector(cancel) 313 | forControlEvents:UIControlEventTouchUpInside]; 314 | 315 | // To be compatible with OS 2.x 316 | #if __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_2_2 317 | _closeButton.font = [UIFont boldSystemFontOfSize:12]; 318 | #else 319 | _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12]; 320 | #endif 321 | 322 | _closeButton.showsTouchWhenHighlighted = YES; 323 | _closeButton.autoresizingMask = UIViewAutoresizingFlexibleRightMargin 324 | | UIViewAutoresizingFlexibleBottomMargin; 325 | [self addSubview:_closeButton]; 326 | 327 | _spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: 328 | UIActivityIndicatorViewStyleWhiteLarge]; 329 | _spinner.autoresizingMask = 330 | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin 331 | | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; 332 | [self addSubview:_spinner]; 333 | _modalBackgroundView = [[UIView alloc] init]; 334 | } 335 | return self; 336 | } 337 | 338 | - (void)dealloc { 339 | _webView.delegate = nil; 340 | [_webView release]; 341 | [_params release]; 342 | [_serverURL release]; 343 | [_spinner release]; 344 | [_closeButton release]; 345 | [_loadingURL release]; 346 | [_modalBackgroundView release]; 347 | [super dealloc]; 348 | } 349 | 350 | /////////////////////////////////////////////////////////////////////////////////////////////////// 351 | // UIView 352 | 353 | - (void)drawRect:(CGRect)rect { 354 | [self drawRect:rect fill:kBorderGray radius:0]; 355 | 356 | CGRect webRect = CGRectMake( 357 | ceil(rect.origin.x + kBorderWidth), ceil(rect.origin.y + kBorderWidth)+1, 358 | rect.size.width - kBorderWidth*2, _webView.frame.size.height+1); 359 | 360 | [self strokeLines:webRect stroke:kBorderBlack]; 361 | } 362 | 363 | /////////////////////////////////////////////////////////////////////////////////////////////////// 364 | // UIWebViewDelegate 365 | 366 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request 367 | navigationType:(UIWebViewNavigationType)navigationType { 368 | NSURL* url = request.URL; 369 | 370 | if ([url.scheme isEqualToString:@"fbconnect"]) { 371 | if ([[url.resourceSpecifier substringToIndex:8] isEqualToString:@"//cancel"]) { 372 | NSString * errorCode = [self getStringFromUrl:[url absoluteString] needle:@"error_code="]; 373 | NSString * errorStr = [self getStringFromUrl:[url absoluteString] needle:@"error_msg="]; 374 | if (errorCode) { 375 | NSDictionary * errorData = [NSDictionary dictionaryWithObject:errorStr forKey:@"error_msg"]; 376 | NSError * error = [NSError errorWithDomain:@"facebookErrDomain" 377 | code:[errorCode intValue] 378 | userInfo:errorData]; 379 | [self dismissWithError:error animated:YES]; 380 | } else { 381 | [self dialogDidCancel:url]; 382 | } 383 | } else { 384 | [self dialogDidSucceed:url]; 385 | } 386 | return NO; 387 | } else if ([_loadingURL isEqual:url]) { 388 | return YES; 389 | } else if (navigationType == UIWebViewNavigationTypeLinkClicked) { 390 | if ([_delegate respondsToSelector:@selector(dialog:shouldOpenURLInExternalBrowser:)]) { 391 | if (![_delegate dialog:self shouldOpenURLInExternalBrowser:url]) { 392 | return NO; 393 | } 394 | } 395 | 396 | [[UIApplication sharedApplication] openURL:request.URL]; 397 | return NO; 398 | } else { 399 | return YES; 400 | } 401 | } 402 | 403 | - (void)webViewDidFinishLoad:(UIWebView *)webView { 404 | [_spinner stopAnimating]; 405 | _spinner.hidden = YES; 406 | 407 | [self updateWebOrientation]; 408 | } 409 | 410 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 411 | // 102 == WebKitErrorFrameLoadInterruptedByPolicyChange 412 | if (!([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102)) { 413 | [self dismissWithError:error animated:YES]; 414 | } 415 | } 416 | 417 | /////////////////////////////////////////////////////////////////////////////////////////////////// 418 | // UIDeviceOrientationDidChangeNotification 419 | 420 | - (void)deviceOrientationDidChange:(void*)object { 421 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 422 | if (!_showingKeyboard && [self shouldRotateToOrientation:orientation]) { 423 | [self updateWebOrientation]; 424 | 425 | CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration; 426 | [UIView beginAnimations:nil context:nil]; 427 | [UIView setAnimationDuration:duration]; 428 | [self sizeToFitOrientation:YES]; 429 | [UIView commitAnimations]; 430 | } 431 | } 432 | 433 | /////////////////////////////////////////////////////////////////////////////////////////////////// 434 | // UIKeyboardNotifications 435 | 436 | - (void)keyboardWillShow:(NSNotification*)notification { 437 | 438 | _showingKeyboard = YES; 439 | 440 | if (FBIsDeviceIPad()) { 441 | // On the iPad the screen is large enough that we don't need to 442 | // resize the dialog to accomodate the keyboard popping up 443 | return; 444 | } 445 | 446 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 447 | if (UIInterfaceOrientationIsLandscape(orientation)) { 448 | _webView.frame = CGRectInset(_webView.frame, 449 | -(kPadding + kBorderWidth), 450 | -(kPadding + kBorderWidth)); 451 | } 452 | } 453 | 454 | - (void)keyboardWillHide:(NSNotification*)notification { 455 | _showingKeyboard = NO; 456 | 457 | if (FBIsDeviceIPad()) { 458 | return; 459 | } 460 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 461 | if (UIInterfaceOrientationIsLandscape(orientation)) { 462 | _webView.frame = CGRectInset(_webView.frame, 463 | kPadding + kBorderWidth, 464 | kPadding + kBorderWidth); 465 | } 466 | } 467 | 468 | ////////////////////////////////////////////////////////////////////////////////////////////////// 469 | // public 470 | 471 | /** 472 | * Find a specific parameter from the url 473 | */ 474 | - (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle { 475 | NSString * str = nil; 476 | NSRange start = [url rangeOfString:needle]; 477 | if (start.location != NSNotFound) { 478 | NSRange end = [[url substringFromIndex:start.location+start.length] rangeOfString:@"&"]; 479 | NSUInteger offset = start.location+start.length; 480 | str = end.location == NSNotFound 481 | ? [url substringFromIndex:offset] 482 | : [url substringWithRange:NSMakeRange(offset, end.location)]; 483 | str = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 484 | } 485 | 486 | return str; 487 | } 488 | 489 | - (id)initWithURL: (NSString *) serverURL 490 | params: (NSMutableDictionary *) params 491 | delegate: (id ) delegate { 492 | 493 | self = [self init]; 494 | _serverURL = [serverURL retain]; 495 | _params = [params retain]; 496 | _delegate = delegate; 497 | 498 | return self; 499 | } 500 | 501 | - (void)load { 502 | [self loadURL:_serverURL get:_params]; 503 | } 504 | 505 | - (void)loadURL:(NSString*)url get:(NSDictionary*)getParams { 506 | 507 | [_loadingURL release]; 508 | _loadingURL = [[self generateURL:url params:getParams] retain]; 509 | NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:_loadingURL]; 510 | 511 | [_webView loadRequest:request]; 512 | } 513 | 514 | - (void)show { 515 | [self load]; 516 | [self sizeToFitOrientation:NO]; 517 | 518 | CGFloat innerWidth = self.frame.size.width - (kBorderWidth+1)*2; 519 | [_closeButton sizeToFit]; 520 | 521 | _closeButton.frame = CGRectMake( 522 | 2, 523 | 2, 524 | 29, 525 | 29); 526 | 527 | _webView.frame = CGRectMake( 528 | kBorderWidth+1, 529 | kBorderWidth+1, 530 | innerWidth, 531 | self.frame.size.height - (1 + kBorderWidth*2)); 532 | 533 | [_spinner sizeToFit]; 534 | [_spinner startAnimating]; 535 | _spinner.center = _webView.center; 536 | 537 | UIWindow* window = [UIApplication sharedApplication].keyWindow; 538 | if (!window) { 539 | window = [[UIApplication sharedApplication].windows objectAtIndex:0]; 540 | } 541 | 542 | _modalBackgroundView.frame = window.frame; 543 | [_modalBackgroundView addSubview:self]; 544 | [window addSubview:_modalBackgroundView]; 545 | 546 | [window addSubview:self]; 547 | 548 | [self dialogWillAppear]; 549 | 550 | self.transform = CGAffineTransformScale([self transformForOrientation], 0.001, 0.001); 551 | [UIView beginAnimations:nil context:nil]; 552 | [UIView setAnimationDuration:kTransitionDuration/1.5]; 553 | [UIView setAnimationDelegate:self]; 554 | [UIView setAnimationDidStopSelector:@selector(bounce1AnimationStopped)]; 555 | self.transform = CGAffineTransformScale([self transformForOrientation], 1.1, 1.1); 556 | [UIView commitAnimations]; 557 | 558 | [self addObservers]; 559 | } 560 | 561 | - (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated { 562 | if (success) { 563 | if ([_delegate respondsToSelector:@selector(dialogDidComplete:)]) { 564 | [_delegate dialogDidComplete:self]; 565 | } 566 | } else { 567 | if ([_delegate respondsToSelector:@selector(dialogDidNotComplete:)]) { 568 | [_delegate dialogDidNotComplete:self]; 569 | } 570 | } 571 | 572 | [self dismiss:animated]; 573 | } 574 | 575 | - (void)dismissWithError:(NSError*)error animated:(BOOL)animated { 576 | if ([_delegate respondsToSelector:@selector(dialog:didFailWithError:)]) { 577 | [_delegate dialog:self didFailWithError:error]; 578 | } 579 | 580 | [self dismiss:animated]; 581 | } 582 | 583 | - (void)dialogWillAppear { 584 | } 585 | 586 | - (void)dialogWillDisappear { 587 | } 588 | 589 | - (void)dialogDidSucceed:(NSURL *)url { 590 | 591 | if ([_delegate respondsToSelector:@selector(dialogCompleteWithUrl:)]) { 592 | [_delegate dialogCompleteWithUrl:url]; 593 | } 594 | [self dismissWithSuccess:YES animated:YES]; 595 | } 596 | 597 | - (void)dialogDidCancel:(NSURL *)url { 598 | if ([_delegate respondsToSelector:@selector(dialogDidNotCompleteWithUrl:)]) { 599 | [_delegate dialogDidNotCompleteWithUrl:url]; 600 | } 601 | [self dismissWithSuccess:NO animated:YES]; 602 | } 603 | 604 | @end 605 | -------------------------------------------------------------------------------- /FBConnect/FBLoginDialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #import "FBDialog.h" 19 | 20 | @protocol FBLoginDialogDelegate; 21 | 22 | /** 23 | * Do not use this interface directly, instead, use authorize in Facebook.h 24 | * 25 | * Facebook Login Dialog interface for start the facebook webView login dialog. 26 | * It start pop-ups prompting for credentials and permissions. 27 | */ 28 | 29 | @interface FBLoginDialog : FBDialog { 30 | id _loginDelegate; 31 | } 32 | 33 | -(id) initWithURL:(NSString *) loginURL 34 | loginParams:(NSMutableDictionary *) params 35 | delegate:(id ) delegate; 36 | @end 37 | 38 | /////////////////////////////////////////////////////////////////////////////////////////////////// 39 | 40 | @protocol FBLoginDialogDelegate 41 | 42 | - (void)fbDialogLogin:(NSString*)token expirationDate:(NSDate*)expirationDate; 43 | 44 | - (void)fbDialogNotLogin:(BOOL)cancelled; 45 | 46 | @end 47 | 48 | 49 | -------------------------------------------------------------------------------- /FBConnect/FBLoginDialog.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "FBDialog.h" 18 | #import "FBLoginDialog.h" 19 | 20 | /////////////////////////////////////////////////////////////////////////////////////////////////// 21 | 22 | @implementation FBLoginDialog 23 | 24 | /////////////////////////////////////////////////////////////////////////////////////////////////// 25 | // public 26 | 27 | /* 28 | * initialize the FBLoginDialog with url and parameters 29 | */ 30 | - (id)initWithURL:(NSString*) loginURL 31 | loginParams:(NSMutableDictionary*) params 32 | delegate:(id ) delegate{ 33 | 34 | self = [super init]; 35 | _serverURL = [loginURL retain]; 36 | _params = [params retain]; 37 | _loginDelegate = delegate; 38 | return self; 39 | } 40 | 41 | /////////////////////////////////////////////////////////////////////////////////////////////////// 42 | // FBDialog 43 | 44 | /** 45 | * Override FBDialog : to call when the webView Dialog did succeed 46 | */ 47 | - (void) dialogDidSucceed:(NSURL*)url { 48 | NSString *q = [url absoluteString]; 49 | NSString *token = [self getStringFromUrl:q needle:@"access_token="]; 50 | NSString *expTime = [self getStringFromUrl:q needle:@"expires_in="]; 51 | NSDate *expirationDate =nil; 52 | 53 | if (expTime != nil) { 54 | int expVal = [expTime intValue]; 55 | if (expVal == 0) { 56 | expirationDate = [NSDate distantFuture]; 57 | } else { 58 | expirationDate = [NSDate dateWithTimeIntervalSinceNow:expVal]; 59 | } 60 | } 61 | 62 | if ((token == (NSString *) [NSNull null]) || (token.length == 0)) { 63 | [self dialogDidCancel:url]; 64 | [self dismissWithSuccess:NO animated:YES]; 65 | } else { 66 | if ([_loginDelegate respondsToSelector:@selector(fbDialogLogin:expirationDate:)]) { 67 | [_loginDelegate fbDialogLogin:token expirationDate:expirationDate]; 68 | } 69 | [self dismissWithSuccess:YES animated:YES]; 70 | } 71 | 72 | } 73 | 74 | /** 75 | * Override FBDialog : to call with the login dialog get canceled 76 | */ 77 | - (void)dialogDidCancel:(NSURL *)url { 78 | [self dismissWithSuccess:NO animated:YES]; 79 | if ([_loginDelegate respondsToSelector:@selector(fbDialogNotLogin:)]) { 80 | [_loginDelegate fbDialogNotLogin:YES]; 81 | } 82 | } 83 | 84 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 85 | if (!(([error.domain isEqualToString:@"NSURLErrorDomain"] && error.code == -999) || 86 | ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102))) { 87 | [super webView:webView didFailLoadWithError:error]; 88 | if ([_loginDelegate respondsToSelector:@selector(fbDialogNotLogin:)]) { 89 | [_loginDelegate fbDialogNotLogin:NO]; 90 | } 91 | } 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /FBConnect/FBRequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | 20 | @protocol FBRequestDelegate; 21 | 22 | enum { 23 | kFBRequestStateReady, 24 | kFBRequestStateLoading, 25 | kFBRequestStateComplete, 26 | kFBRequestStateError 27 | }; 28 | typedef NSUInteger FBRequestState; 29 | 30 | /** 31 | * Do not use this interface directly, instead, use method in Facebook.h 32 | */ 33 | @interface FBRequest : NSObject { 34 | id _delegate; 35 | NSString* _url; 36 | NSString* _httpMethod; 37 | NSMutableDictionary* _params; 38 | NSURLConnection* _connection; 39 | NSMutableData* _responseText; 40 | FBRequestState _state; 41 | NSError* _error; 42 | } 43 | 44 | 45 | @property(nonatomic,assign) id delegate; 46 | 47 | /** 48 | * The URL which will be contacted to execute the request. 49 | */ 50 | @property(nonatomic,copy) NSString* url; 51 | 52 | /** 53 | * The API method which will be called. 54 | */ 55 | @property(nonatomic,copy) NSString* httpMethod; 56 | 57 | /** 58 | * The dictionary of parameters to pass to the method. 59 | * 60 | * These values in the dictionary will be converted to strings using the 61 | * standard Objective-C object-to-string conversion facilities. 62 | */ 63 | @property(nonatomic,retain) NSMutableDictionary* params; 64 | @property(nonatomic,retain) NSURLConnection* connection; 65 | @property(nonatomic,retain) NSMutableData* responseText; 66 | @property(nonatomic,readonly) FBRequestState state; 67 | 68 | /** 69 | * Error returned by the server in case of request's failure (or nil otherwise). 70 | */ 71 | @property(nonatomic,retain) NSError* error; 72 | 73 | 74 | + (NSString*)serializeURL:(NSString *)baseUrl 75 | params:(NSDictionary *)params; 76 | 77 | + (NSString*)serializeURL:(NSString *)baseUrl 78 | params:(NSDictionary *)params 79 | httpMethod:(NSString *)httpMethod; 80 | 81 | + (FBRequest*)getRequestWithParams:(NSMutableDictionary *) params 82 | httpMethod:(NSString *) httpMethod 83 | delegate:(id)delegate 84 | requestURL:(NSString *) url; 85 | - (BOOL) loading; 86 | 87 | - (void) connect; 88 | 89 | @end 90 | 91 | //////////////////////////////////////////////////////////////////////////////// 92 | 93 | /* 94 | *Your application should implement this delegate 95 | */ 96 | @protocol FBRequestDelegate 97 | 98 | @optional 99 | 100 | /** 101 | * Called just before the request is sent to the server. 102 | */ 103 | - (void)requestLoading:(FBRequest *)request; 104 | 105 | /** 106 | * Called when the server responds and begins to send back data. 107 | */ 108 | - (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response; 109 | 110 | /** 111 | * Called when an error prevents the request from completing successfully. 112 | */ 113 | - (void)request:(FBRequest *)request didFailWithError:(NSError *)error; 114 | 115 | /** 116 | * Called when a request returns and its response has been parsed into 117 | * an object. 118 | * 119 | * The resulting object may be a dictionary, an array, a string, or a number, 120 | * depending on thee format of the API response. 121 | */ 122 | - (void)request:(FBRequest *)request didLoad:(id)result; 123 | 124 | /** 125 | * Called when a request returns a response. 126 | * 127 | * The result object is the raw response from the server of type NSData 128 | */ 129 | - (void)request:(FBRequest *)request didLoadRawResponse:(NSData *)data; 130 | 131 | @end 132 | 133 | -------------------------------------------------------------------------------- /FBConnect/FBRequest.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "FBRequest.h" 18 | #import "JSON.h" 19 | 20 | /////////////////////////////////////////////////////////////////////////////////////////////////// 21 | // global 22 | 23 | static NSString* kUserAgent = @"FacebookConnect"; 24 | static NSString* kStringBoundary = @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f"; 25 | static const int kGeneralErrorCode = 10000; 26 | 27 | static const NSTimeInterval kTimeoutInterval = 180.0; 28 | 29 | /////////////////////////////////////////////////////////////////////////////////////////////////// 30 | 31 | @interface FBRequest () 32 | @property (nonatomic,readwrite) FBRequestState state; 33 | @end 34 | 35 | @implementation FBRequest 36 | 37 | @synthesize delegate = _delegate, 38 | url = _url, 39 | httpMethod = _httpMethod, 40 | params = _params, 41 | connection = _connection, 42 | responseText = _responseText, 43 | state = _state, 44 | error = _error; 45 | ////////////////////////////////////////////////////////////////////////////////////////////////// 46 | // class public 47 | 48 | + (FBRequest *)getRequestWithParams:(NSMutableDictionary *) params 49 | httpMethod:(NSString *) httpMethod 50 | delegate:(id) delegate 51 | requestURL:(NSString *) url { 52 | 53 | FBRequest* request = [[[FBRequest alloc] init] autorelease]; 54 | request.delegate = delegate; 55 | request.url = url; 56 | request.httpMethod = httpMethod; 57 | request.params = params; 58 | request.connection = nil; 59 | request.responseText = nil; 60 | 61 | return request; 62 | } 63 | 64 | /////////////////////////////////////////////////////////////////////////////////////////////////// 65 | // private 66 | 67 | + (NSString *)serializeURL:(NSString *)baseUrl 68 | params:(NSDictionary *)params { 69 | return [self serializeURL:baseUrl params:params httpMethod:@"GET"]; 70 | } 71 | 72 | /** 73 | * Generate get URL 74 | */ 75 | + (NSString*)serializeURL:(NSString *)baseUrl 76 | params:(NSDictionary *)params 77 | httpMethod:(NSString *)httpMethod { 78 | 79 | NSURL* parsedURL = [NSURL URLWithString:baseUrl]; 80 | NSString* queryPrefix = parsedURL.query ? @"&" : @"?"; 81 | 82 | NSMutableArray* pairs = [NSMutableArray array]; 83 | for (NSString* key in [params keyEnumerator]) { 84 | if (([[params valueForKey:key] isKindOfClass:[UIImage class]]) 85 | ||([[params valueForKey:key] isKindOfClass:[NSData class]])) { 86 | if ([httpMethod isEqualToString:@"GET"]) { 87 | NSLog(@"can not use GET to upload a file"); 88 | } 89 | continue; 90 | } 91 | 92 | NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes( 93 | NULL, /* allocator */ 94 | (CFStringRef)[params objectForKey:key], 95 | NULL, /* charactersToLeaveUnescaped */ 96 | (CFStringRef)@"!*'();:@&=+$,/?%#[]", 97 | kCFStringEncodingUTF8); 98 | 99 | [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, escaped_value]]; 100 | [escaped_value release]; 101 | } 102 | NSString* query = [pairs componentsJoinedByString:@"&"]; 103 | 104 | return [NSString stringWithFormat:@"%@%@%@", baseUrl, queryPrefix, query]; 105 | } 106 | 107 | /** 108 | * Body append for POST method 109 | */ 110 | - (void)utfAppendBody:(NSMutableData *)body data:(NSString *)data { 111 | [body appendData:[data dataUsingEncoding:NSUTF8StringEncoding]]; 112 | } 113 | 114 | /** 115 | * Generate body for POST method 116 | */ 117 | - (NSMutableData *)generatePostBody { 118 | NSMutableData *body = [NSMutableData data]; 119 | NSString *endLine = [NSString stringWithFormat:@"\r\n--%@\r\n", kStringBoundary]; 120 | NSMutableDictionary *dataDictionary = [NSMutableDictionary dictionary]; 121 | 122 | [self utfAppendBody:body data:[NSString stringWithFormat:@"--%@\r\n", kStringBoundary]]; 123 | 124 | for (id key in [_params keyEnumerator]) { 125 | 126 | if (([[_params valueForKey:key] isKindOfClass:[UIImage class]]) 127 | ||([[_params valueForKey:key] isKindOfClass:[NSData class]])) { 128 | 129 | [dataDictionary setObject:[_params valueForKey:key] forKey:key]; 130 | continue; 131 | 132 | } 133 | 134 | [self utfAppendBody:body 135 | data:[NSString 136 | stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", 137 | key]]; 138 | [self utfAppendBody:body data:[_params valueForKey:key]]; 139 | 140 | [self utfAppendBody:body data:endLine]; 141 | } 142 | 143 | if ([dataDictionary count] > 0) { 144 | for (id key in dataDictionary) { 145 | NSObject *dataParam = [dataDictionary valueForKey:key]; 146 | if ([dataParam isKindOfClass:[UIImage class]]) { 147 | NSData* imageData = UIImagePNGRepresentation((UIImage*)dataParam); 148 | [self utfAppendBody:body 149 | data:[NSString stringWithFormat: 150 | @"Content-Disposition: form-data; filename=\"%@\"\r\n", key]]; 151 | [self utfAppendBody:body 152 | data:[NSString stringWithString:@"Content-Type: image/png\r\n\r\n"]]; 153 | [body appendData:imageData]; 154 | } else { 155 | NSAssert([dataParam isKindOfClass:[NSData class]], 156 | @"dataParam must be a UIImage or NSData"); 157 | [self utfAppendBody:body 158 | data:[NSString stringWithFormat: 159 | @"Content-Disposition: form-data; filename=\"%@\"\r\n", key]]; 160 | [self utfAppendBody:body 161 | data:[NSString stringWithString:@"Content-Type: content/unknown\r\n\r\n"]]; 162 | [body appendData:(NSData*)dataParam]; 163 | } 164 | [self utfAppendBody:body data:endLine]; 165 | 166 | } 167 | } 168 | 169 | return body; 170 | } 171 | 172 | /** 173 | * Formulate the NSError 174 | */ 175 | - (id)formError:(NSInteger)code userInfo:(NSDictionary *) errorData { 176 | return [NSError errorWithDomain:@"facebookErrDomain" code:code userInfo:errorData]; 177 | 178 | } 179 | 180 | /** 181 | * parse the response data 182 | */ 183 | - (id)parseJsonResponse:(NSData *)data error:(NSError **)error { 184 | 185 | NSString* responseString = [[[NSString alloc] initWithData:data 186 | encoding:NSUTF8StringEncoding] 187 | autorelease]; 188 | SBJSON *jsonParser = [[SBJSON new] autorelease]; 189 | if ([responseString isEqualToString:@"true"]) { 190 | return [NSDictionary dictionaryWithObject:@"true" forKey:@"result"]; 191 | } else if ([responseString isEqualToString:@"false"]) { 192 | if (error != nil) { 193 | *error = [self formError:kGeneralErrorCode 194 | userInfo:[NSDictionary 195 | dictionaryWithObject:@"This operation can not be completed" 196 | forKey:@"error_msg"]]; 197 | } 198 | return nil; 199 | } 200 | 201 | 202 | id result = [jsonParser objectWithString:responseString]; 203 | 204 | if (![result isKindOfClass:[NSArray class]]) { 205 | if ([result objectForKey:@"error"] != nil) { 206 | if (error != nil) { 207 | *error = [self formError:kGeneralErrorCode 208 | userInfo:result]; 209 | } 210 | return nil; 211 | } 212 | 213 | if ([result objectForKey:@"error_code"] != nil) { 214 | if (error != nil) { 215 | *error = [self formError:[[result objectForKey:@"error_code"] intValue] userInfo:result]; 216 | } 217 | return nil; 218 | } 219 | 220 | if ([result objectForKey:@"error_msg"] != nil) { 221 | if (error != nil) { 222 | *error = [self formError:kGeneralErrorCode userInfo:result]; 223 | } 224 | } 225 | 226 | if ([result objectForKey:@"error_reason"] != nil) { 227 | if (error != nil) { 228 | *error = [self formError:kGeneralErrorCode userInfo:result]; 229 | } 230 | } 231 | } 232 | 233 | return result; 234 | 235 | } 236 | 237 | /* 238 | * private helper function: call the delegate function when the request 239 | * fails with error 240 | */ 241 | - (void)failWithError:(NSError *)error { 242 | if ([_delegate respondsToSelector:@selector(request:didFailWithError:)]) { 243 | [_delegate request:self didFailWithError:error]; 244 | } 245 | self.state = kFBRequestStateError; 246 | } 247 | 248 | /* 249 | * private helper function: handle the response data 250 | */ 251 | - (void)handleResponseData:(NSData *)data { 252 | if ([_delegate respondsToSelector: 253 | @selector(request:didLoadRawResponse:)]) { 254 | [_delegate request:self didLoadRawResponse:data]; 255 | } 256 | 257 | NSError* error = nil; 258 | id result = [self parseJsonResponse:data error:&error]; 259 | self.error = error; 260 | 261 | if ([_delegate respondsToSelector:@selector(request:didLoad:)] || 262 | [_delegate respondsToSelector: 263 | @selector(request:didFailWithError:)]) { 264 | 265 | if (error) { 266 | [self failWithError:error]; 267 | } else if ([_delegate respondsToSelector: 268 | @selector(request:didLoad:)]) { 269 | [_delegate request:self didLoad:(result == nil ? data : result)]; 270 | } 271 | 272 | } 273 | 274 | } 275 | 276 | 277 | 278 | ////////////////////////////////////////////////////////////////////////////////////////////////// 279 | // public 280 | 281 | /** 282 | * @return boolean - whether this request is processing 283 | */ 284 | - (BOOL)loading { 285 | return !!_connection; 286 | } 287 | 288 | /** 289 | * make the Facebook request 290 | */ 291 | - (void)connect { 292 | 293 | if ([_delegate respondsToSelector:@selector(requestLoading:)]) { 294 | [_delegate requestLoading:self]; 295 | } 296 | 297 | NSString* url = [[self class] serializeURL:_url params:_params httpMethod:_httpMethod]; 298 | NSMutableURLRequest* request = 299 | [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] 300 | cachePolicy:NSURLRequestReloadIgnoringLocalCacheData 301 | timeoutInterval:kTimeoutInterval]; 302 | [request setValue:kUserAgent forHTTPHeaderField:@"User-Agent"]; 303 | 304 | 305 | [request setHTTPMethod:self.httpMethod]; 306 | if ([self.httpMethod isEqualToString: @"POST"]) { 307 | NSString* contentType = [NSString 308 | stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; 309 | [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; 310 | 311 | [request setHTTPBody:[self generatePostBody]]; 312 | } 313 | 314 | _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 315 | self.state = kFBRequestStateLoading; 316 | } 317 | 318 | /** 319 | * Free internal structure 320 | */ 321 | - (void)dealloc { 322 | [_connection cancel]; 323 | [_connection release]; 324 | [_responseText release]; 325 | [_url release]; 326 | [_httpMethod release]; 327 | [_params release]; 328 | [super dealloc]; 329 | } 330 | 331 | ////////////////////////////////////////////////////////////////////////////////////////////////// 332 | // NSURLConnectionDelegate 333 | 334 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 335 | _responseText = [[NSMutableData alloc] init]; 336 | 337 | NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; 338 | if ([_delegate respondsToSelector: 339 | @selector(request:didReceiveResponse:)]) { 340 | [_delegate request:self didReceiveResponse:httpResponse]; 341 | } 342 | } 343 | 344 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 345 | [_responseText appendData:data]; 346 | } 347 | 348 | - (NSCachedURLResponse *)connection:(NSURLConnection *)connection 349 | willCacheResponse:(NSCachedURLResponse*)cachedResponse { 350 | return nil; 351 | } 352 | 353 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 354 | [self handleResponseData:_responseText]; 355 | 356 | self.responseText = nil; 357 | self.connection = nil; 358 | 359 | if (self.state != kFBRequestStateError) { 360 | self.state = kFBRequestStateComplete; 361 | } 362 | } 363 | 364 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 365 | [self failWithError:error]; 366 | 367 | self.responseText = nil; 368 | self.connection = nil; 369 | 370 | self.state = kFBRequestStateError; 371 | } 372 | 373 | @end 374 | -------------------------------------------------------------------------------- /FBConnect/Facebook.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "FBLoginDialog.h" 18 | #import "FBRequest.h" 19 | 20 | @protocol FBSessionDelegate; 21 | 22 | /** 23 | * Main Facebook interface for interacting with the Facebook developer API. 24 | * Provides methods to log in and log out a user, make requests using the REST 25 | * and Graph APIs, and start user interface interactions (such as 26 | * pop-ups promoting for credentials, permissions, stream posts, etc.) 27 | */ 28 | @interface Facebook : NSObject{ 29 | NSString* _accessToken; 30 | NSDate* _expirationDate; 31 | id _sessionDelegate; 32 | NSMutableSet* _requests; 33 | FBDialog* _loginDialog; 34 | FBDialog* _fbDialog; 35 | NSString* _appId; 36 | NSString* _urlSchemeSuffix; 37 | NSArray* _permissions; 38 | } 39 | 40 | @property(nonatomic, copy) NSString* accessToken; 41 | @property(nonatomic, copy) NSDate* expirationDate; 42 | @property(nonatomic, assign) id sessionDelegate; 43 | @property(nonatomic, copy) NSString* urlSchemeSuffix; 44 | 45 | - (id)initWithAppId:(NSString *)appId 46 | andDelegate:(id)delegate; 47 | 48 | - (id)initWithAppId:(NSString *)appId 49 | urlSchemeSuffix:(NSString *)urlSchemeSuffix 50 | andDelegate:(id)delegate; 51 | 52 | - (void)authorize:(NSArray *)permissions; 53 | 54 | - (BOOL)handleOpenURL:(NSURL *)url; 55 | 56 | - (void)logout; 57 | 58 | - (FBRequest*)requestWithParams:(NSMutableDictionary *)params 59 | andDelegate:(id )delegate; 60 | 61 | - (FBRequest*)requestWithMethodName:(NSString *)methodName 62 | andParams:(NSMutableDictionary *)params 63 | andHttpMethod:(NSString *)httpMethod 64 | andDelegate:(id )delegate; 65 | 66 | - (FBRequest*)requestWithGraphPath:(NSString *)graphPath 67 | andDelegate:(id )delegate; 68 | 69 | - (FBRequest*)requestWithGraphPath:(NSString *)graphPath 70 | andParams:(NSMutableDictionary *)params 71 | andDelegate:(id )delegate; 72 | 73 | - (FBRequest*)requestWithGraphPath:(NSString *)graphPath 74 | andParams:(NSMutableDictionary *)params 75 | andHttpMethod:(NSString *)httpMethod 76 | andDelegate:(id )delegate; 77 | 78 | - (void)dialog:(NSString *)action 79 | andDelegate:(id)delegate; 80 | 81 | - (void)dialog:(NSString *)action 82 | andParams:(NSMutableDictionary *)params 83 | andDelegate:(id )delegate; 84 | 85 | - (BOOL)isSessionValid; 86 | 87 | @end 88 | 89 | //////////////////////////////////////////////////////////////////////////////// 90 | 91 | /** 92 | * Your application should implement this delegate to receive session callbacks. 93 | */ 94 | @protocol FBSessionDelegate 95 | 96 | @optional 97 | 98 | /** 99 | * Called when the user successfully logged in. 100 | */ 101 | - (void)fbDidLogin; 102 | 103 | /** 104 | * Called when the user dismissed the dialog without logging in. 105 | */ 106 | - (void)fbDidNotLogin:(BOOL)cancelled; 107 | 108 | /** 109 | * Called when the user logged out. 110 | */ 111 | - (void)fbDidLogout; 112 | 113 | /** 114 | * Called when the current session has expired. This might happen when: 115 | * - the access token expired 116 | * - the app has been disabled 117 | * - the user revoked the app's permissions 118 | * - the user changed his or her password 119 | */ 120 | - (void)fbSessionInvalidated; 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /FBConnect/JSON/JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | /** 31 | @mainpage A strict JSON parser and generator for Objective-C 32 | 33 | JSON (JavaScript Object Notation) is a lightweight data-interchange 34 | format. This framework provides two apis for parsing and generating 35 | JSON. One standard object-based and a higher level api consisting of 36 | categories added to existing Objective-C classes. 37 | 38 | Learn more on the http://code.google.com/p/json-framework project site. 39 | 40 | This framework does its best to be as strict as possible, both in what it 41 | accepts and what it generates. For example, it does not support trailing commas 42 | in arrays or objects. Nor does it support embedded comments, or 43 | anything else not in the JSON specification. This is considered a feature. 44 | 45 | */ 46 | 47 | #import "SBJSON.h" 48 | #import "NSObject+SBJSON.h" 49 | #import "NSString+SBJSON.h" 50 | 51 | -------------------------------------------------------------------------------- /FBConnect/JSON/NSObject+SBJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | 33 | /** 34 | @brief Adds JSON generation to Foundation classes 35 | 36 | This is a category on NSObject that adds methods for returning JSON representations 37 | of standard objects to the objects themselves. This means you can call the 38 | -JSONRepresentation method on an NSArray object and it'll do what you want. 39 | */ 40 | @interface NSObject (NSObject_SBJSON) 41 | 42 | /** 43 | @brief Returns a string containing the receiver encoded as a JSON fragment. 44 | 45 | This method is added as a category on NSObject but is only actually 46 | supported for the following objects: 47 | @li NSDictionary 48 | @li NSArray 49 | @li NSString 50 | @li NSNumber (also used for booleans) 51 | @li NSNull 52 | 53 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 54 | */ 55 | - (NSString *)JSONFragment; 56 | 57 | /** 58 | @brief Returns a string containing the receiver encoded in JSON. 59 | 60 | This method is added as a category on NSObject but is only actually 61 | supported for the following objects: 62 | @li NSDictionary 63 | @li NSArray 64 | */ 65 | - (NSString *)JSONRepresentation; 66 | 67 | @end 68 | 69 | -------------------------------------------------------------------------------- /FBConnect/JSON/NSObject+SBJSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "NSObject+SBJSON.h" 31 | #import "SBJsonWriter.h" 32 | 33 | @implementation NSObject (NSObject_SBJSON) 34 | 35 | - (NSString *)JSONFragment { 36 | SBJsonWriter *jsonWriter = [SBJsonWriter new]; 37 | NSString *json = [jsonWriter stringWithFragment:self]; 38 | if (!json) 39 | NSLog(@"-JSONFragment failed. Error trace is: %@", [jsonWriter errorTrace]); 40 | [jsonWriter release]; 41 | return json; 42 | } 43 | 44 | - (NSString *)JSONRepresentation { 45 | SBJsonWriter *jsonWriter = [SBJsonWriter new]; 46 | NSString *json = [jsonWriter stringWithObject:self]; 47 | if (!json) 48 | NSLog(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]); 49 | [jsonWriter release]; 50 | return json; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /FBConnect/JSON/NSString+SBJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | /** 33 | @brief Adds JSON parsing methods to NSString 34 | 35 | This is a category on NSString that adds methods for parsing the target string. 36 | */ 37 | @interface NSString (NSString_SBJSON) 38 | 39 | 40 | /** 41 | @brief Returns the object represented in the receiver, or nil on error. 42 | 43 | Returns a a scalar object represented by the string's JSON fragment representation. 44 | 45 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 46 | */ 47 | - (id)JSONFragmentValue; 48 | 49 | /** 50 | @brief Returns the NSDictionary or NSArray represented by the current string's JSON representation. 51 | 52 | Returns the dictionary or array represented in the receiver, or nil on error. 53 | 54 | Returns the NSDictionary or NSArray represented by the current string's JSON representation. 55 | */ 56 | - (id)JSONValue; 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /FBConnect/JSON/NSString+SBJSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "NSString+SBJSON.h" 31 | #import "SBJsonParser.h" 32 | 33 | @implementation NSString (NSString_SBJSON) 34 | 35 | - (id)JSONFragmentValue 36 | { 37 | SBJsonParser *jsonParser = [SBJsonParser new]; 38 | id repr = [jsonParser fragmentWithString:self]; 39 | if (!repr) 40 | NSLog(@"-JSONFragmentValue failed. Error trace is: %@", [jsonParser errorTrace]); 41 | [jsonParser release]; 42 | return repr; 43 | } 44 | 45 | - (id)JSONValue 46 | { 47 | SBJsonParser *jsonParser = [SBJsonParser new]; 48 | id repr = [jsonParser objectWithString:self]; 49 | if (!repr) 50 | NSLog(@"-JSONValue failed. Error trace is: %@", [jsonParser errorTrace]); 51 | [jsonParser release]; 52 | return repr; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /FBConnect/JSON/SBJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | #import "SBJsonParser.h" 32 | #import "SBJsonWriter.h" 33 | 34 | /** 35 | @brief Facade for SBJsonWriter/SBJsonParser. 36 | 37 | Requests are forwarded to instances of SBJsonWriter and SBJsonParser. 38 | */ 39 | @interface SBJSON : SBJsonBase { 40 | 41 | @private 42 | SBJsonParser *jsonParser; 43 | SBJsonWriter *jsonWriter; 44 | } 45 | 46 | 47 | /// Return the fragment represented by the given string 48 | - (id)fragmentWithString:(NSString*)jsonrep 49 | error:(NSError**)error; 50 | 51 | /// Return the object represented by the given string 52 | - (id)objectWithString:(NSString*)jsonrep 53 | error:(NSError**)error; 54 | 55 | /// Parse the string and return the represented object (or scalar) 56 | - (id)objectWithString:(id)value 57 | allowScalar:(BOOL)x 58 | error:(NSError**)error; 59 | 60 | 61 | /// Return JSON representation of an array or dictionary 62 | - (NSString*)stringWithObject:(id)value 63 | error:(NSError**)error; 64 | 65 | /// Return JSON representation of any legal JSON value 66 | - (NSString*)stringWithFragment:(id)value 67 | error:(NSError**)error; 68 | 69 | /// Return JSON representation (or fragment) for the given object 70 | - (NSString*)stringWithObject:(id)value 71 | allowScalar:(BOOL)x 72 | error:(NSError**)error; 73 | 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /FBConnect/JSON/SBJSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJSON.h" 31 | 32 | @implementation SBJSON 33 | 34 | - (id)init { 35 | self = [super init]; 36 | if (self) { 37 | jsonWriter = [SBJsonWriter new]; 38 | jsonParser = [SBJsonParser new]; 39 | [self setMaxDepth:512]; 40 | 41 | } 42 | return self; 43 | } 44 | 45 | - (void)dealloc { 46 | [jsonWriter release]; 47 | [jsonParser release]; 48 | [super dealloc]; 49 | } 50 | 51 | #pragma mark Writer 52 | 53 | 54 | - (NSString *)stringWithObject:(id)obj { 55 | NSString *repr = [jsonWriter stringWithObject:obj]; 56 | if (repr) 57 | return repr; 58 | 59 | [errorTrace release]; 60 | errorTrace = [[jsonWriter errorTrace] mutableCopy]; 61 | return nil; 62 | } 63 | 64 | /** 65 | Returns a string containing JSON representation of the passed in value, or nil on error. 66 | If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. 67 | 68 | @param value any instance that can be represented as a JSON fragment 69 | @param allowScalar wether to return json fragments for scalar objects 70 | @param error used to return an error by reference (pass NULL if this is not desired) 71 | 72 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 73 | */ 74 | - (NSString*)stringWithObject:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { 75 | 76 | NSString *json = allowScalar ? [jsonWriter stringWithFragment:value] : [jsonWriter stringWithObject:value]; 77 | if (json) 78 | return json; 79 | 80 | [errorTrace release]; 81 | errorTrace = [[jsonWriter errorTrace] mutableCopy]; 82 | 83 | if (error) 84 | *error = [errorTrace lastObject]; 85 | return nil; 86 | } 87 | 88 | /** 89 | Returns a string containing JSON representation of the passed in value, or nil on error. 90 | If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. 91 | 92 | @param value any instance that can be represented as a JSON fragment 93 | @param error used to return an error by reference (pass NULL if this is not desired) 94 | 95 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 96 | */ 97 | - (NSString*)stringWithFragment:(id)value error:(NSError**)error { 98 | return [self stringWithObject:value 99 | allowScalar:YES 100 | error:error]; 101 | } 102 | 103 | /** 104 | Returns a string containing JSON representation of the passed in value, or nil on error. 105 | If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. 106 | 107 | @param value a NSDictionary or NSArray instance 108 | @param error used to return an error by reference (pass NULL if this is not desired) 109 | */ 110 | - (NSString*)stringWithObject:(id)value error:(NSError**)error { 111 | return [self stringWithObject:value 112 | allowScalar:NO 113 | error:error]; 114 | } 115 | 116 | #pragma mark Parsing 117 | 118 | - (id)objectWithString:(NSString *)repr { 119 | id obj = [jsonParser objectWithString:repr]; 120 | if (obj) 121 | return obj; 122 | 123 | [errorTrace release]; 124 | errorTrace = [[jsonParser errorTrace] mutableCopy]; 125 | 126 | return nil; 127 | } 128 | 129 | /** 130 | Returns the object represented by the passed-in string or nil on error. The returned object can be 131 | a string, number, boolean, null, array or dictionary. 132 | 133 | @param value the json string to parse 134 | @param allowScalar whether to return objects for JSON fragments 135 | @param error used to return an error by reference (pass NULL if this is not desired) 136 | 137 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 138 | */ 139 | - (id)objectWithString:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { 140 | 141 | id obj = allowScalar ? [jsonParser fragmentWithString:value] : [jsonParser objectWithString:value]; 142 | if (obj) 143 | return obj; 144 | 145 | [errorTrace release]; 146 | errorTrace = [[jsonParser errorTrace] mutableCopy]; 147 | 148 | if (error) 149 | *error = [errorTrace lastObject]; 150 | return nil; 151 | } 152 | 153 | /** 154 | Returns the object represented by the passed-in string or nil on error. The returned object can be 155 | a string, number, boolean, null, array or dictionary. 156 | 157 | @param repr the json string to parse 158 | @param error used to return an error by reference (pass NULL if this is not desired) 159 | 160 | @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. 161 | */ 162 | - (id)fragmentWithString:(NSString*)repr error:(NSError**)error { 163 | return [self objectWithString:repr 164 | allowScalar:YES 165 | error:error]; 166 | } 167 | 168 | /** 169 | Returns the object represented by the passed-in string or nil on error. The returned object 170 | will be either a dictionary or an array. 171 | 172 | @param repr the json string to parse 173 | @param error used to return an error by reference (pass NULL if this is not desired) 174 | */ 175 | - (id)objectWithString:(NSString*)repr error:(NSError**)error { 176 | return [self objectWithString:repr 177 | allowScalar:NO 178 | error:error]; 179 | } 180 | 181 | 182 | 183 | #pragma mark Properties - parsing 184 | 185 | - (NSUInteger)maxDepth { 186 | return jsonParser.maxDepth; 187 | } 188 | 189 | - (void)setMaxDepth:(NSUInteger)d { 190 | jsonWriter.maxDepth = jsonParser.maxDepth = d; 191 | } 192 | 193 | 194 | #pragma mark Properties - writing 195 | 196 | - (BOOL)humanReadable { 197 | return jsonWriter.humanReadable; 198 | } 199 | 200 | - (void)setHumanReadable:(BOOL)x { 201 | jsonWriter.humanReadable = x; 202 | } 203 | 204 | - (BOOL)sortKeys { 205 | return jsonWriter.sortKeys; 206 | } 207 | 208 | - (void)setSortKeys:(BOOL)x { 209 | jsonWriter.sortKeys = x; 210 | } 211 | 212 | @end 213 | -------------------------------------------------------------------------------- /FBConnect/JSON/SBJsonBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | extern NSString * SBJSONErrorDomain; 33 | 34 | 35 | enum { 36 | EUNSUPPORTED = 1, 37 | EPARSENUM, 38 | EPARSE, 39 | EFRAGMENT, 40 | ECTRL, 41 | EUNICODE, 42 | EDEPTH, 43 | EESCAPE, 44 | ETRAILCOMMA, 45 | ETRAILGARBAGE, 46 | EEOF, 47 | EINPUT 48 | }; 49 | 50 | /** 51 | @brief Common base class for parsing & writing. 52 | 53 | This class contains the common error-handling code and option between the parser/writer. 54 | */ 55 | @interface SBJsonBase : NSObject { 56 | NSMutableArray *errorTrace; 57 | 58 | @protected 59 | NSUInteger depth, maxDepth; 60 | } 61 | 62 | /** 63 | @brief The maximum recursing depth. 64 | 65 | Defaults to 512. If the input is nested deeper than this the input will be deemed to be 66 | malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can 67 | turn off this security feature by setting the maxDepth value to 0. 68 | */ 69 | @property NSUInteger maxDepth; 70 | 71 | /** 72 | @brief Return an error trace, or nil if there was no errors. 73 | 74 | Note that this method returns the trace of the last method that failed. 75 | You need to check the return value of the call you're making to figure out 76 | if the call actually failed, before you know call this method. 77 | */ 78 | @property(copy,readonly) NSArray* errorTrace; 79 | 80 | /// @internal for use in subclasses to add errors to the stack trace 81 | - (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str; 82 | 83 | /// @internal for use in subclasess to clear the error before a new parsing attempt 84 | - (void)clearErrorTrace; 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /FBConnect/JSON/SBJsonBase.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonBase.h" 31 | NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain"; 32 | 33 | 34 | @implementation SBJsonBase 35 | 36 | @synthesize errorTrace; 37 | @synthesize maxDepth; 38 | 39 | - (id)init { 40 | self = [super init]; 41 | if (self) 42 | self.maxDepth = 512; 43 | return self; 44 | } 45 | 46 | - (void)dealloc { 47 | [errorTrace release]; 48 | [super dealloc]; 49 | } 50 | 51 | - (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str { 52 | NSDictionary *userInfo; 53 | if (!errorTrace) { 54 | errorTrace = [NSMutableArray new]; 55 | userInfo = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey]; 56 | 57 | } else { 58 | userInfo = [NSDictionary dictionaryWithObjectsAndKeys: 59 | str, NSLocalizedDescriptionKey, 60 | [errorTrace lastObject], NSUnderlyingErrorKey, 61 | nil]; 62 | } 63 | 64 | NSError *error = [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:userInfo]; 65 | 66 | [self willChangeValueForKey:@"errorTrace"]; 67 | [errorTrace addObject:error]; 68 | [self didChangeValueForKey:@"errorTrace"]; 69 | } 70 | 71 | - (void)clearErrorTrace { 72 | [self willChangeValueForKey:@"errorTrace"]; 73 | [errorTrace release]; 74 | errorTrace = nil; 75 | [self didChangeValueForKey:@"errorTrace"]; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /FBConnect/JSON/SBJsonParser.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | #import "SBJsonBase.h" 32 | 33 | /** 34 | @brief Options for the parser class. 35 | 36 | This exists so the SBJSON facade can implement the options in the parser without having to re-declare them. 37 | */ 38 | @protocol SBJsonParser 39 | 40 | /** 41 | @brief Return the object represented by the given string. 42 | 43 | Returns the object represented by the passed-in string or nil on error. The returned object can be 44 | a string, number, boolean, null, array or dictionary. 45 | 46 | @param repr the json string to parse 47 | */ 48 | - (id)objectWithString:(NSString *)repr; 49 | 50 | @end 51 | 52 | 53 | /** 54 | @brief The JSON parser class. 55 | 56 | JSON is mapped to Objective-C types in the following way: 57 | 58 | @li Null -> NSNull 59 | @li String -> NSMutableString 60 | @li Array -> NSMutableArray 61 | @li Object -> NSMutableDictionary 62 | @li Boolean -> NSNumber (initialised with -initWithBool:) 63 | @li Number -> NSDecimalNumber 64 | 65 | Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber 66 | instances. These are initialised with the -initWithBool: method, and 67 | round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be 68 | represented as 'true' and 'false' again.) 69 | 70 | JSON numbers turn into NSDecimalNumber instances, 71 | as we can thus avoid any loss of precision. (JSON allows ridiculously large numbers.) 72 | 73 | */ 74 | @interface SBJsonParser : SBJsonBase { 75 | 76 | @private 77 | const char *c; 78 | } 79 | 80 | @end 81 | 82 | // don't use - exists for backwards compatibility with 2.1.x only. Will be removed in 2.3. 83 | @interface SBJsonParser (Private) 84 | - (id)fragmentWithString:(id)repr; 85 | @end 86 | 87 | 88 | -------------------------------------------------------------------------------- /FBConnect/JSON/SBJsonParser.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonParser.h" 31 | 32 | @interface SBJsonParser () 33 | 34 | - (BOOL)scanValue:(NSObject **)o; 35 | 36 | - (BOOL)scanRestOfArray:(NSMutableArray **)o; 37 | - (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o; 38 | - (BOOL)scanRestOfNull:(NSNull **)o; 39 | - (BOOL)scanRestOfFalse:(NSNumber **)o; 40 | - (BOOL)scanRestOfTrue:(NSNumber **)o; 41 | - (BOOL)scanRestOfString:(NSMutableString **)o; 42 | 43 | // Cannot manage without looking at the first digit 44 | - (BOOL)scanNumber:(NSNumber **)o; 45 | 46 | - (BOOL)scanHexQuad:(unichar *)x; 47 | - (BOOL)scanUnicodeChar:(unichar *)x; 48 | 49 | - (BOOL)scanIsAtEnd; 50 | 51 | @end 52 | 53 | #define skipWhitespace(c) while (isspace(*c)) c++ 54 | #define skipDigits(c) while (isdigit(*c)) c++ 55 | 56 | 57 | @implementation SBJsonParser 58 | 59 | static char ctrl[0x22]; 60 | 61 | 62 | + (void)initialize { 63 | ctrl[0] = '\"'; 64 | ctrl[1] = '\\'; 65 | for (int i = 1; i < 0x20; i++) 66 | ctrl[i+1] = i; 67 | ctrl[0x21] = 0; 68 | } 69 | 70 | /** 71 | @deprecated This exists in order to provide fragment support in older APIs in one more version. 72 | It should be removed in the next major version. 73 | */ 74 | - (id)fragmentWithString:(id)repr { 75 | [self clearErrorTrace]; 76 | 77 | if (!repr) { 78 | [self addErrorWithCode:EINPUT description:@"Input was 'nil'"]; 79 | return nil; 80 | } 81 | 82 | depth = 0; 83 | c = [repr UTF8String]; 84 | 85 | id o; 86 | if (![self scanValue:&o]) { 87 | return nil; 88 | } 89 | 90 | // We found some valid JSON. But did it also contain something else? 91 | if (![self scanIsAtEnd]) { 92 | [self addErrorWithCode:ETRAILGARBAGE description:@"Garbage after JSON"]; 93 | return nil; 94 | } 95 | 96 | NSAssert1(o, @"Should have a valid object from %@", repr); 97 | return o; 98 | } 99 | 100 | - (id)objectWithString:(NSString *)repr { 101 | 102 | id o = [self fragmentWithString:repr]; 103 | if (!o) 104 | return nil; 105 | 106 | // Check that the object we've found is a valid JSON container. 107 | if (![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) { 108 | [self addErrorWithCode:EFRAGMENT description:@"Valid fragment, but not JSON"]; 109 | return nil; 110 | } 111 | 112 | return o; 113 | } 114 | 115 | /* 116 | In contrast to the public methods, it is an error to omit the error parameter here. 117 | */ 118 | - (BOOL)scanValue:(NSObject **)o 119 | { 120 | skipWhitespace(c); 121 | 122 | switch (*c++) { 123 | case '{': 124 | return [self scanRestOfDictionary:(NSMutableDictionary **)o]; 125 | break; 126 | case '[': 127 | return [self scanRestOfArray:(NSMutableArray **)o]; 128 | break; 129 | case '"': 130 | return [self scanRestOfString:(NSMutableString **)o]; 131 | break; 132 | case 'f': 133 | return [self scanRestOfFalse:(NSNumber **)o]; 134 | break; 135 | case 't': 136 | return [self scanRestOfTrue:(NSNumber **)o]; 137 | break; 138 | case 'n': 139 | return [self scanRestOfNull:(NSNull **)o]; 140 | break; 141 | case '-': 142 | case '0'...'9': 143 | c--; // cannot verify number correctly without the first character 144 | return [self scanNumber:(NSNumber **)o]; 145 | break; 146 | case '+': 147 | [self addErrorWithCode:EPARSENUM description: @"Leading + disallowed in number"]; 148 | return NO; 149 | break; 150 | case 0x0: 151 | [self addErrorWithCode:EEOF description:@"Unexpected end of string"]; 152 | return NO; 153 | break; 154 | default: 155 | [self addErrorWithCode:EPARSE description: @"Unrecognised leading character"]; 156 | return NO; 157 | break; 158 | } 159 | 160 | NSAssert(0, @"Should never get here"); 161 | return NO; 162 | } 163 | 164 | - (BOOL)scanRestOfTrue:(NSNumber **)o 165 | { 166 | if (!strncmp(c, "rue", 3)) { 167 | c += 3; 168 | *o = [NSNumber numberWithBool:YES]; 169 | return YES; 170 | } 171 | [self addErrorWithCode:EPARSE description:@"Expected 'true'"]; 172 | return NO; 173 | } 174 | 175 | - (BOOL)scanRestOfFalse:(NSNumber **)o 176 | { 177 | if (!strncmp(c, "alse", 4)) { 178 | c += 4; 179 | *o = [NSNumber numberWithBool:NO]; 180 | return YES; 181 | } 182 | [self addErrorWithCode:EPARSE description: @"Expected 'false'"]; 183 | return NO; 184 | } 185 | 186 | - (BOOL)scanRestOfNull:(NSNull **)o { 187 | if (!strncmp(c, "ull", 3)) { 188 | c += 3; 189 | *o = [NSNull null]; 190 | return YES; 191 | } 192 | [self addErrorWithCode:EPARSE description: @"Expected 'null'"]; 193 | return NO; 194 | } 195 | 196 | - (BOOL)scanRestOfArray:(NSMutableArray **)o { 197 | if (maxDepth && ++depth > maxDepth) { 198 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 199 | return NO; 200 | } 201 | 202 | *o = [NSMutableArray arrayWithCapacity:8]; 203 | 204 | for (; *c ;) { 205 | id v; 206 | 207 | skipWhitespace(c); 208 | if (*c == ']' && c++) { 209 | depth--; 210 | return YES; 211 | } 212 | 213 | if (![self scanValue:&v]) { 214 | [self addErrorWithCode:EPARSE description:@"Expected value while parsing array"]; 215 | return NO; 216 | } 217 | 218 | [*o addObject:v]; 219 | 220 | skipWhitespace(c); 221 | if (*c == ',' && c++) { 222 | skipWhitespace(c); 223 | if (*c == ']') { 224 | [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in array"]; 225 | return NO; 226 | } 227 | } 228 | } 229 | 230 | [self addErrorWithCode:EEOF description: @"End of input while parsing array"]; 231 | return NO; 232 | } 233 | 234 | - (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o 235 | { 236 | if (maxDepth && ++depth > maxDepth) { 237 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 238 | return NO; 239 | } 240 | 241 | *o = [NSMutableDictionary dictionaryWithCapacity:7]; 242 | 243 | for (; *c ;) { 244 | id k, v; 245 | 246 | skipWhitespace(c); 247 | if (*c == '}' && c++) { 248 | depth--; 249 | return YES; 250 | } 251 | 252 | if (!(*c == '\"' && c++ && [self scanRestOfString:&k])) { 253 | [self addErrorWithCode:EPARSE description: @"Object key string expected"]; 254 | return NO; 255 | } 256 | 257 | skipWhitespace(c); 258 | if (*c != ':') { 259 | [self addErrorWithCode:EPARSE description: @"Expected ':' separating key and value"]; 260 | return NO; 261 | } 262 | 263 | c++; 264 | if (![self scanValue:&v]) { 265 | NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k]; 266 | [self addErrorWithCode:EPARSE description: string]; 267 | return NO; 268 | } 269 | 270 | [*o setObject:v forKey:k]; 271 | 272 | skipWhitespace(c); 273 | if (*c == ',' && c++) { 274 | skipWhitespace(c); 275 | if (*c == '}') { 276 | [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in object"]; 277 | return NO; 278 | } 279 | } 280 | } 281 | 282 | [self addErrorWithCode:EEOF description: @"End of input while parsing object"]; 283 | return NO; 284 | } 285 | 286 | - (BOOL)scanRestOfString:(NSMutableString **)o 287 | { 288 | *o = [NSMutableString stringWithCapacity:16]; 289 | do { 290 | // First see if there's a portion we can grab in one go. 291 | // Doing this caused a massive speedup on the long string. 292 | size_t len = strcspn(c, ctrl); 293 | if (len) { 294 | // check for 295 | id t = [[NSString alloc] initWithBytesNoCopy:(char*)c 296 | length:len 297 | encoding:NSUTF8StringEncoding 298 | freeWhenDone:NO]; 299 | if (t) { 300 | [*o appendString:t]; 301 | [t release]; 302 | c += len; 303 | } 304 | } 305 | 306 | if (*c == '"') { 307 | c++; 308 | return YES; 309 | 310 | } else if (*c == '\\') { 311 | unichar uc = *++c; 312 | switch (uc) { 313 | case '\\': 314 | case '/': 315 | case '"': 316 | break; 317 | 318 | case 'b': uc = '\b'; break; 319 | case 'n': uc = '\n'; break; 320 | case 'r': uc = '\r'; break; 321 | case 't': uc = '\t'; break; 322 | case 'f': uc = '\f'; break; 323 | 324 | case 'u': 325 | c++; 326 | if (![self scanUnicodeChar:&uc]) { 327 | [self addErrorWithCode:EUNICODE description: @"Broken unicode character"]; 328 | return NO; 329 | } 330 | c--; // hack. 331 | break; 332 | default: 333 | [self addErrorWithCode:EESCAPE description: [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]]; 334 | return NO; 335 | break; 336 | } 337 | CFStringAppendCharacters((CFMutableStringRef)*o, &uc, 1); 338 | c++; 339 | 340 | } else if (*c < 0x20) { 341 | [self addErrorWithCode:ECTRL description: [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]]; 342 | return NO; 343 | 344 | } else { 345 | NSLog(@"should not be able to get here"); 346 | } 347 | } while (*c); 348 | 349 | [self addErrorWithCode:EEOF description:@"Unexpected EOF while parsing string"]; 350 | return NO; 351 | } 352 | 353 | - (BOOL)scanUnicodeChar:(unichar *)x 354 | { 355 | unichar hi, lo; 356 | 357 | if (![self scanHexQuad:&hi]) { 358 | [self addErrorWithCode:EUNICODE description: @"Missing hex quad"]; 359 | return NO; 360 | } 361 | 362 | if (hi >= 0xd800) { // high surrogate char? 363 | if (hi < 0xdc00) { // yes - expect a low char 364 | 365 | if (!(*c == '\\' && ++c && *c == 'u' && ++c && [self scanHexQuad:&lo])) { 366 | [self addErrorWithCode:EUNICODE description: @"Missing low character in surrogate pair"]; 367 | return NO; 368 | } 369 | 370 | if (lo < 0xdc00 || lo >= 0xdfff) { 371 | [self addErrorWithCode:EUNICODE description:@"Invalid low surrogate char"]; 372 | return NO; 373 | } 374 | 375 | hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000; 376 | 377 | } else if (hi < 0xe000) { 378 | [self addErrorWithCode:EUNICODE description:@"Invalid high character in surrogate pair"]; 379 | return NO; 380 | } 381 | } 382 | 383 | *x = hi; 384 | return YES; 385 | } 386 | 387 | - (BOOL)scanHexQuad:(unichar *)x 388 | { 389 | *x = 0; 390 | for (int i = 0; i < 4; i++) { 391 | unichar uc = *c; 392 | c++; 393 | int d = (uc >= '0' && uc <= '9') 394 | ? uc - '0' : (uc >= 'a' && uc <= 'f') 395 | ? (uc - 'a' + 10) : (uc >= 'A' && uc <= 'F') 396 | ? (uc - 'A' + 10) : -1; 397 | if (d == -1) { 398 | [self addErrorWithCode:EUNICODE description:@"Missing hex digit in quad"]; 399 | return NO; 400 | } 401 | *x *= 16; 402 | *x += d; 403 | } 404 | return YES; 405 | } 406 | 407 | - (BOOL)scanNumber:(NSNumber **)o 408 | { 409 | const char *ns = c; 410 | 411 | // The logic to test for validity of the number formatting is relicensed 412 | // from JSON::XS with permission from its author Marc Lehmann. 413 | // (Available at the CPAN: http://search.cpan.org/dist/JSON-XS/ .) 414 | 415 | if ('-' == *c) 416 | c++; 417 | 418 | if ('0' == *c && c++) { 419 | if (isdigit(*c)) { 420 | [self addErrorWithCode:EPARSENUM description: @"Leading 0 disallowed in number"]; 421 | return NO; 422 | } 423 | 424 | } else if (!isdigit(*c) && c != ns) { 425 | [self addErrorWithCode:EPARSENUM description: @"No digits after initial minus"]; 426 | return NO; 427 | 428 | } else { 429 | skipDigits(c); 430 | } 431 | 432 | // Fractional part 433 | if ('.' == *c && c++) { 434 | 435 | if (!isdigit(*c)) { 436 | [self addErrorWithCode:EPARSENUM description: @"No digits after decimal point"]; 437 | return NO; 438 | } 439 | skipDigits(c); 440 | } 441 | 442 | // Exponential part 443 | if ('e' == *c || 'E' == *c) { 444 | c++; 445 | 446 | if ('-' == *c || '+' == *c) 447 | c++; 448 | 449 | if (!isdigit(*c)) { 450 | [self addErrorWithCode:EPARSENUM description: @"No digits after exponent"]; 451 | return NO; 452 | } 453 | skipDigits(c); 454 | } 455 | 456 | id str = [[NSString alloc] initWithBytesNoCopy:(char*)ns 457 | length:c - ns 458 | encoding:NSUTF8StringEncoding 459 | freeWhenDone:NO]; 460 | [str autorelease]; 461 | if (str && (*o = [NSDecimalNumber decimalNumberWithString:str])) 462 | return YES; 463 | 464 | [self addErrorWithCode:EPARSENUM description: @"Failed creating decimal instance"]; 465 | return NO; 466 | } 467 | 468 | - (BOOL)scanIsAtEnd 469 | { 470 | skipWhitespace(c); 471 | return !*c; 472 | } 473 | 474 | 475 | @end 476 | -------------------------------------------------------------------------------- /FBConnect/JSON/SBJsonWriter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | #import "SBJsonBase.h" 32 | 33 | /** 34 | @brief Options for the writer class. 35 | 36 | This exists so the SBJSON facade can implement the options in the writer without having to re-declare them. 37 | */ 38 | @protocol SBJsonWriter 39 | 40 | /** 41 | @brief Whether we are generating human-readable (multiline) JSON. 42 | 43 | Set whether or not to generate human-readable JSON. The default is NO, which produces 44 | JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable 45 | JSON with linebreaks after each array value and dictionary key/value pair, indented two 46 | spaces per nesting level. 47 | */ 48 | @property BOOL humanReadable; 49 | 50 | /** 51 | @brief Whether or not to sort the dictionary keys in the output. 52 | 53 | If this is set to YES, the dictionary keys in the JSON output will be in sorted order. 54 | (This is useful if you need to compare two structures, for example.) The default is NO. 55 | */ 56 | @property BOOL sortKeys; 57 | 58 | /** 59 | @brief Return JSON representation (or fragment) for the given object. 60 | 61 | Returns a string containing JSON representation of the passed in value, or nil on error. 62 | If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. 63 | 64 | @param value any instance that can be represented as a JSON fragment 65 | 66 | */ 67 | - (NSString*)stringWithObject:(id)value; 68 | 69 | @end 70 | 71 | 72 | /** 73 | @brief The JSON writer class. 74 | 75 | Objective-C types are mapped to JSON types in the following way: 76 | 77 | @li NSNull -> Null 78 | @li NSString -> String 79 | @li NSArray -> Array 80 | @li NSDictionary -> Object 81 | @li NSNumber (-initWithBool:) -> Boolean 82 | @li NSNumber -> Number 83 | 84 | In JSON the keys of an object must be strings. NSDictionary keys need 85 | not be, but attempting to convert an NSDictionary with non-string keys 86 | into JSON will throw an exception. 87 | 88 | NSNumber instances created with the +initWithBool: method are 89 | converted into the JSON boolean "true" and "false" values, and vice 90 | versa. Any other NSNumber instances are converted to a JSON number the 91 | way you would expect. 92 | 93 | */ 94 | @interface SBJsonWriter : SBJsonBase { 95 | 96 | @private 97 | BOOL sortKeys, humanReadable; 98 | } 99 | 100 | @end 101 | 102 | // don't use - exists for backwards compatibility. Will be removed in 2.3. 103 | @interface SBJsonWriter (Private) 104 | - (NSString*)stringWithFragment:(id)value; 105 | @end 106 | 107 | /** 108 | @brief Allows generation of JSON for otherwise unsupported classes. 109 | 110 | If you have a custom class that you want to create a JSON representation for you can implement 111 | this method in your class. It should return a representation of your object defined 112 | in terms of objects that can be translated into JSON. For example, a Person 113 | object might implement it like this: 114 | 115 | @code 116 | - (id)jsonProxyObject { 117 | return [NSDictionary dictionaryWithObjectsAndKeys: 118 | name, @"name", 119 | phone, @"phone", 120 | email, @"email", 121 | nil]; 122 | } 123 | @endcode 124 | 125 | */ 126 | @interface NSObject (SBProxyForJson) 127 | - (id)proxyForJson; 128 | @end 129 | 130 | -------------------------------------------------------------------------------- /FBConnect/JSON/SBJsonWriter.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonWriter.h" 31 | 32 | @interface SBJsonWriter () 33 | 34 | - (BOOL)appendValue:(id)fragment into:(NSMutableString*)json; 35 | - (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json; 36 | - (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json; 37 | - (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json; 38 | 39 | - (NSString*)indent; 40 | 41 | @end 42 | 43 | @implementation SBJsonWriter 44 | 45 | static NSMutableCharacterSet *kEscapeChars; 46 | 47 | + (void)initialize { 48 | kEscapeChars = [[NSMutableCharacterSet characterSetWithRange: NSMakeRange(0,32)] retain]; 49 | [kEscapeChars addCharactersInString: @"\"\\"]; 50 | } 51 | 52 | 53 | @synthesize sortKeys; 54 | @synthesize humanReadable; 55 | 56 | /** 57 | @deprecated This exists in order to provide fragment support in older APIs in one more version. 58 | It should be removed in the next major version. 59 | */ 60 | - (NSString*)stringWithFragment:(id)value { 61 | [self clearErrorTrace]; 62 | depth = 0; 63 | NSMutableString *json = [NSMutableString stringWithCapacity:128]; 64 | 65 | if ([self appendValue:value into:json]) 66 | return json; 67 | 68 | return nil; 69 | } 70 | 71 | 72 | - (NSString*)stringWithObject:(id)value { 73 | 74 | if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) { 75 | return [self stringWithFragment:value]; 76 | } 77 | 78 | if ([value respondsToSelector:@selector(proxyForJson)]) { 79 | NSString *tmp = [self stringWithObject:[value proxyForJson]]; 80 | if (tmp) 81 | return tmp; 82 | } 83 | 84 | 85 | [self clearErrorTrace]; 86 | [self addErrorWithCode:EFRAGMENT description:@"Not valid type for JSON"]; 87 | return nil; 88 | } 89 | 90 | 91 | - (NSString*)indent { 92 | return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0]; 93 | } 94 | 95 | - (BOOL)appendValue:(id)fragment into:(NSMutableString*)json { 96 | if ([fragment isKindOfClass:[NSDictionary class]]) { 97 | if (![self appendDictionary:fragment into:json]) 98 | return NO; 99 | 100 | } else if ([fragment isKindOfClass:[NSArray class]]) { 101 | if (![self appendArray:fragment into:json]) 102 | return NO; 103 | 104 | } else if ([fragment isKindOfClass:[NSString class]]) { 105 | if (![self appendString:fragment into:json]) 106 | return NO; 107 | 108 | } else if ([fragment isKindOfClass:[NSNumber class]]) { 109 | if ('c' == *[fragment objCType]) 110 | [json appendString:[fragment boolValue] ? @"true" : @"false"]; 111 | else 112 | [json appendString:[fragment stringValue]]; 113 | 114 | } else if ([fragment isKindOfClass:[NSNull class]]) { 115 | [json appendString:@"null"]; 116 | } else if ([fragment respondsToSelector:@selector(proxyForJson)]) { 117 | [self appendValue:[fragment proxyForJson] into:json]; 118 | 119 | } else { 120 | [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]]; 121 | return NO; 122 | } 123 | return YES; 124 | } 125 | 126 | - (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json { 127 | if (maxDepth && ++depth > maxDepth) { 128 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 129 | return NO; 130 | } 131 | [json appendString:@"["]; 132 | 133 | BOOL addComma = NO; 134 | for (id value in fragment) { 135 | if (addComma) 136 | [json appendString:@","]; 137 | else 138 | addComma = YES; 139 | 140 | if ([self humanReadable]) 141 | [json appendString:[self indent]]; 142 | 143 | if (![self appendValue:value into:json]) { 144 | return NO; 145 | } 146 | } 147 | 148 | depth--; 149 | if ([self humanReadable] && [fragment count]) 150 | [json appendString:[self indent]]; 151 | [json appendString:@"]"]; 152 | return YES; 153 | } 154 | 155 | - (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json { 156 | if (maxDepth && ++depth > maxDepth) { 157 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 158 | return NO; 159 | } 160 | [json appendString:@"{"]; 161 | 162 | NSString *colon = [self humanReadable] ? @" : " : @":"; 163 | BOOL addComma = NO; 164 | NSArray *keys = [fragment allKeys]; 165 | if (self.sortKeys) 166 | keys = [keys sortedArrayUsingSelector:@selector(compare:)]; 167 | 168 | for (id value in keys) { 169 | if (addComma) 170 | [json appendString:@","]; 171 | else 172 | addComma = YES; 173 | 174 | if ([self humanReadable]) 175 | [json appendString:[self indent]]; 176 | 177 | if (![value isKindOfClass:[NSString class]]) { 178 | [self addErrorWithCode:EUNSUPPORTED description: @"JSON object key must be string"]; 179 | return NO; 180 | } 181 | 182 | if (![self appendString:value into:json]) 183 | return NO; 184 | 185 | [json appendString:colon]; 186 | if (![self appendValue:[fragment objectForKey:value] into:json]) { 187 | [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"Unsupported value for key %@ in object", value]]; 188 | return NO; 189 | } 190 | } 191 | 192 | depth--; 193 | if ([self humanReadable] && [fragment count]) 194 | [json appendString:[self indent]]; 195 | [json appendString:@"}"]; 196 | return YES; 197 | } 198 | 199 | - (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json { 200 | 201 | [json appendString:@"\""]; 202 | 203 | NSRange esc = [fragment rangeOfCharacterFromSet:kEscapeChars]; 204 | if ( !esc.length ) { 205 | // No special chars -- can just add the raw string: 206 | [json appendString:fragment]; 207 | 208 | } else { 209 | NSUInteger length = [fragment length]; 210 | for (NSUInteger i = 0; i < length; i++) { 211 | unichar uc = [fragment characterAtIndex:i]; 212 | switch (uc) { 213 | case '"': [json appendString:@"\\\""]; break; 214 | case '\\': [json appendString:@"\\\\"]; break; 215 | case '\t': [json appendString:@"\\t"]; break; 216 | case '\n': [json appendString:@"\\n"]; break; 217 | case '\r': [json appendString:@"\\r"]; break; 218 | case '\b': [json appendString:@"\\b"]; break; 219 | case '\f': [json appendString:@"\\f"]; break; 220 | default: 221 | if (uc < 0x20) { 222 | [json appendFormat:@"\\u%04x", uc]; 223 | } else { 224 | CFStringAppendCharacters((CFMutableStringRef)json, &uc, 1); 225 | } 226 | break; 227 | 228 | } 229 | } 230 | } 231 | 232 | [json appendString:@"\""]; 233 | return YES; 234 | } 235 | 236 | 237 | @end 238 | -------------------------------------------------------------------------------- /FBConnect/README.mdown: -------------------------------------------------------------------------------- 1 | Facebook iOS SDK 2 | =========================== 3 | 4 | This open source iOS library allows you to integrate Facebook into your iOS application include iPhone, iPad and iPod touch. 5 | 6 | Except as otherwise noted, the Facebook iOS SDK is licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html) 7 | 8 | Getting Started 9 | =============== 10 | 11 | The SDK is lightweight and has no external dependencies. Getting started is easy. 12 | 13 | Setup Your Environment 14 | ---------------------- 15 | 16 | * If you haven't already done so, set up your iPhone development environment by following the [iPhone Dev Center Getting Started Documents](https://developer.apple.com/iphone/index.action). 17 | 18 | * Install [Git](http://git-scm.com/). 19 | 20 | * Pull this SDK from GitHub: 21 | 22 | git clone git://github.com/facebook/facebook-ios-sdk.git 23 | 24 | Sample Applications 25 | ------------------- 26 | 27 | This SDK comes with a sample application that demonstrates authorization, making API calls, and invoking a dialog, to guide you in development. 28 | 29 | To build and run the sample application with Xcode (3.2): 30 | 31 | * Open the included Xcode Project File by selecting _File_->_Open..._ and selecting sample/DemoApp/DemoApp.xcodeproj. 32 | 33 | * Verify your compiler settings by checking the menu items under _Project_->_Set Active SDK_ and _Project_->_Set Active Executable_. For most developers, the defaults should be OK. Note that if you compile against a version of the iOS SDK that does not support multitasking, not all features of the Facebook SDK may be available. See the "Debugging" section below for more information. 34 | 35 | * Create a Facebook App ID (see http://www.facebook.com/developers/createapp.php) 36 | 37 | * Specify your Facebook AppId in DemoAppViewController.m and DemoApp-Info.plist (under URL types > Item 0 > URL Schemes > Item 0) 38 | 39 | * Finally, select _Build_->_Build and Run_. This should compile the application and launch it. 40 | 41 | Integrate With Your Own Application 42 | ----------------------------------- 43 | 44 | If you want to integrate Facebook with an existing application, then follow these steps: 45 | 46 | * Copy the Facebook SDK into your Xcode project: 47 | * In Xcode, open the Facebook SDK by selecting _File_->_Open..._ and selecting src/facebook-ios-sdk.xcodeproj. 48 | * With your own application project open in Xcode, drag and drop the "FBConnect" folder from the Facebook SDK project into your application's project. 49 | * Include the FBConnect headers in your code: 50 | 51 | #import "FBConnect/FBConnect.h" 52 | 53 | * You should now be able to compile your project successfully. 54 | 55 | * Register your application with Facebook: 56 | * Create a new Facebook application at: http://www.facebook.com/developers/createapp.php. If you already have a related web application, you can use the same application ID. 57 | * Set your application's name and picture. This is what users will see when they authorize your application. 58 | 59 | Usage 60 | ----- 61 | 62 | Begin by instantiating the Facebook object: 63 | 64 | Facebook* facebook = [[Facebook alloc] initWithAppId:appId]; 65 | 66 | Where _appId_ is your Facebook application ID string. 67 | 68 | With the iOS SDK, you can do three main things: 69 | 70 | * Authentication and Authorization: Prompt users to log in to Facebook and grant permissions to your application. 71 | 72 | * Make API Calls: Fetch user profile data, as well as information about a user's friends. 73 | 74 | * Display a Dialog: Interact with a user via a UIWebView--this is useful for enabling quick Facebook interactions (such as publishing to a user's stream) without requiring upfront permissions or implementing a native UI. 75 | 76 | Authentication and Authorization 77 | -------------------------------- 78 | 79 | Authorizing a user allows your application to make authenticated API calls on the user's behalf. By default your application will have access to the user's basic information, including their name, profile picture, and their list of friends, along with any other information the user has made public. If your application requires access to private information, it may request (http://developers.facebook.com/docs/authentication/permissions)[additional permissions]. 80 | 81 | To authorize a user, do the following: 82 | 83 | * Bind your application to a URL scheme corresponding to your Facebook application ID. The URL scheme you must bind to is of the format "fb\[appId\]://", where \[appId\] is your Facebook application ID. Without this, your application won't be able to handle authorization callbacks. Modify your application's _.plist_ file as follows: 84 | 85 | * Under the root key ("Information Property List") add a new row and name the key "URL types". 86 | * Under the "URL types" key that you just added, you should see a key named "Item 0". If not, add a new row with key "Item 0". 87 | * Under the "Item 0" key, add a new row and name the key "URL Schemes". 88 | * Under the "URL Schemes" key that you just added, you should see a key named "Item 0". If not, add a new row with key "Item 0". 89 | * Set the value of "Item 0" to "fb\[appId\]" where \[appId\] is your Facebook application ID. Make sure there are no spaces anywhere in this value. For example, if your application's id is 1234, the value should be "fb1234". 90 | 91 | * Modify your application's main AppDelegate class as follows: 92 | 93 | * Add a method with the following signature (if it doesn't exist alrady): 94 | 95 | - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url 96 | 97 | * In this method, call your application's Facebook object's _handleOpenURL_ method, making sure to pass in the _url_ parameter. 98 | 99 | * Finally, make a call to the _authorize_ method: 100 | 101 | Facebook* facebook = [[Facebook alloc] initWithAppId:appId]; 102 | [facebook authorize:permissions delegate:self]; 103 | 104 | Where _appId_ is your Facebook application ID string, _permissions_ is an array of strings containing each permission your application requires, and _delegate_ is the delegate object you wish to receive callbacks. For more information, refer to the code or sample application. 105 | 106 | See the sample application for a more specific code example. 107 | 108 | Single Sign-On 109 | -------------- 110 | 111 | In the initial release of the SDK, the authorize method always opened an inline dialog containing a UIWebView in which the authorization UI was shown to the user. Each iOS application has its own cookie jar, so this mechnism had a major disadvantage: it required users to enter their credentials separately for each app they authorized. 112 | 113 | In the updated version of the SDK, we changed the authorization mechanism so that users no longer have to re-enter their credentials for every application on the device they want to authorize. The new mechanism relies on iOS's fast app switching. It works as follows: 114 | 115 | If the app is running in a version of iOS that supports multitasking, and if the device has the Facebook app of version 3.2.3 or greater installed, the SDK attempts to open the authorization dialog withing the Facebook app. After the user grants or declines the authorization, the Facebook app redirects back to the calling app, passing the authorization token, expiration, and any other parameters the Facebook OAuth server may return. 116 | 117 | If the device is running in a version of iOS that supports multitasking, but it doesn't have the Facebook app of version 3.2.3 or greater installed, the SDK will open the authorization dialog in Safari. After the user grants or revokes the authorization, Safari redirects back to the calling app. Similar to the Facebook app based authorization, this allows multiple applications to share the same Facebook user session through the Safari cookie. 118 | 119 | If the app is running a version of iOS that does not support multitasking, the SDK uses the old mechanism of popping up an inline UIWebView, prompting the user to log in and grant access. The FBSessionDelegate is a callback interface that your application should implement: it's methods will be invoked when the application successful login or logout. 120 | 121 | Logging Out 122 | ----------- 123 | 124 | When the user wants to stop using Facebook integration with your application, you can call the logout method to clear all application state and make a server request to invalidate the current access token. 125 | 126 | [facebook logout:self]; 127 | 128 | Note that logging out will not revoke your application's permissions, but simply clears your application's access token. If a user that has previously logged out of your application returns, he will simply see a notification that he's logging into your application, not a notification to grant permissions. To modify or revoke an application's permissions, a user must visit the ["Applications, Games, and Websites" tab of their Facebook privacy settings dashboard](http://www.facebook.com/settings/?tab=privacy). 129 | 130 | 131 | Making API Calls 132 | ---------------- 133 | 134 | The [Facebook Graph API](http://developers.facebook.com/docs/api) presents a simple, consistent view of the Facebook social graph, uniformly representing objects in the graph (e.g., people, photos, events, and fan pages) and the connections between them (e.g., friend relationships, shared content, and photo tags). 135 | 136 | You can access the Graph API by passing the Graph Path to the request() method. For example, to access information about the logged in user, call 137 | 138 | [facebook requestWithGraphPath:@"me" andDelegate:self]; // get information about the currently logged in user 139 | [facebook requestWithGraphPath:@"platform/posts" andDelegate:self]; // get the posts made by the "platform" page 140 | [facebook requestWithGraphPath:@"me/friends" andDelegate:self]; // get the logged-in user's friends 141 | 142 | Your delegate object should implement the FBRequestDelegate interface to handle your request responses. 143 | 144 | Note that the server response will be in JSON string format. The SDK uses an open source JSON library (http://code.google.com/p/json-framework/) to parse the result. If a parsing error occurs, the SDK will callback request:didFailWithError: in your delegate. 145 | 146 | A successful request will callback request:didLoad: in your delegate. The result passed to your delegate can be an NSArray, if there are multiple results, or an NSDictionary if there is only a single result. 147 | 148 | Advanced applications may want to provide their own custom parsing and/or error handling, depending on their individual needs. 149 | 150 | The [Old REST API](http://developers.facebook.com/docs/reference/rest/) is also supported. To access REST methods, pass in the named parameters and the method name as an NSDictionary. 151 | 152 | NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"4", @"uids", @"name", @"fields", nil]; 153 | [facebook requestWithMethodName: @"users.getInfo" andParams: params andHttpMethod: @"GET" andDelegate: self]; 154 | 155 | 156 | 157 | Displaying Dialogs 158 | ------------------ 159 | 160 | This SDK provides a method for popping up a Facebook dialog. The currently supported dialogs are the login and permissions dialogs used in the authorization flow, and a dialog for publishing posts to a user's feed. 161 | 162 | To invoke a dialog: 163 | 164 | [facebook dialog:@"feed" andDelegate:self]; 165 | 166 | This allows you to provide basic Facebook functionality in your application with a singe line of code -- no need to build native dialogs, make API calls, or handle responses. For further examples, refer to the included sample application. 167 | 168 | Error Handling 169 | -------------- 170 | 171 | Errors are handled by the FBRequestDelegate and FBDialogDelegate interfaces. Applications can implement these interfaces and specify delegates as necessary to handle any errors. 172 | 173 | Debugging 174 | --------- 175 | 176 | Common problems and solutions: 177 | 178 | * The sample app won't run. What's the deal? 179 | 180 | Check the setup instructions inline with the code and make sure you've set your Facebook application ID in DemoAppViewController.kAppId. 181 | 182 | * What version of the iOS SDK must I compile my application against to use single sign-on? 183 | 184 | Single sign-on is available for apps built on version of iOS that support multitasking (generall v4.0 and higher--see Apple documentation for more information). Others applications will fall back to inline dialog-based authorization. 185 | 186 | * What version of the Facebook Application must a user have installed to use single sign-on? 187 | 188 | The Facebook Application version 3.2.3 or higher will support single sign-on. Users with older versions will gracefully fall back to inline dialog-based authorization. 189 | 190 | * During single sign-on, the Facebook application isn't redirecting back to my application after a user authorizes it. What's wrong? 191 | 192 | Make sure you've edited your application's .plist file properly, so that your applicaition binds to the fb\[appId\]:// URL scheme (where "\[appId\]" is your Facebook application ID). 193 | 194 | * After upgrading to Xcode 4 the Demo app will not build and I get the following error: [BEROR]No architectures to compile for (ARCHS=i386, VALID_ARCHS=armv7 armv6). What should I do? 195 | 196 | Edit your build settings and add i386 to the list of valid architectures for the app. Click the project icon in the project navigator, select the DemoApp project, Build Settings tab, Architecture section, Valid Architectures option. Then click the grey arrow to expand, and double-click on right of Debug. After "armv6 armv7" add "i386". 197 | -------------------------------------------------------------------------------- /FacebookLikeView/Classes/Facebook+ForceDialog.m: -------------------------------------------------------------------------------- 1 | // 2 | // Facebook+ForceDialog.m 3 | // Yardsellr 4 | // 5 | // Created by Thomas Brow on 12/10/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "Facebook.h" 11 | 12 | // Suppress clang's warning about overriding in a category 13 | #pragma clang diagnostic push 14 | #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" 15 | 16 | @implementation Facebook(ForceDialog) 17 | 18 | - (void)authorize:(NSArray *)permissions { 19 | // Hack to force Facebook SDK to always use in-app dialog for auth 20 | [_permissions release]; 21 | _permissions = [permissions retain]; 22 | 23 | objc_msgSend(self, @selector(authorizeWithFBAppAuth:safariAuth:), NO, NO); 24 | } 25 | 26 | @end 27 | 28 | #pragma clang diagnostic pop 29 | -------------------------------------------------------------------------------- /FacebookLikeView/Classes/FacebookLikeView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FacebookLikeView.h 3 | // Yardsellr 4 | // 5 | // Created by Tom Brow on 5/9/11. 6 | // Copyright 2011 Yardsellr. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol FacebookLikeViewDelegate; 12 | 13 | @interface FacebookLikeView : UIView 14 | 15 | // A delegate 16 | @property (unsafe_unretained) IBOutlet id delegate; 17 | 18 | // The URL to like. This and the following properties map directly to XFBML attributes 19 | // described here: https://developers.facebook.com/docs/reference/plugins/like/ 20 | @property (strong, nonatomic) NSURL *href; 21 | 22 | // The style of the Like button and like count. Options: 'standard', 'button_count', and 'box_count'. 23 | // You are responsible for sizing your FacebookLikeView appropriately for the layout you choose. 24 | @property (strong, nonatomic) NSString *layout; 25 | 26 | // Specifies whether to display profile photos below the button ('standard' layout only) 27 | @property (assign, nonatomic) BOOL showFaces; 28 | 29 | // The verb to display on the button. Options: 'like', 'recommend' 30 | @property (strong, nonatomic) NSString *action; 31 | 32 | // The font to display in the button. Options: 'arial', 'lucida grande', 'segoe ui', 'tahoma', 'trebuchet ms', 'verdana' 33 | @property (strong, nonatomic) NSString *font; 34 | 35 | // The color scheme for the like button. Options: 'light', 'dark' 36 | @property (strong, nonatomic) NSString *colorScheme; 37 | 38 | // A label for tracking referrals. 39 | @property (strong, nonatomic) NSString *ref; 40 | 41 | // Load/reload the content of the web view. You should call this after changing any of the above parameters, 42 | // and whenever the user signs in or out of Facebook. 43 | - (void)load; 44 | 45 | @end 46 | 47 | @protocol FacebookLikeViewDelegate 48 | 49 | // Called when user taps Like button or "sign in" link when not logged in. Your implementation should present 50 | // the user with a Facebook login dialog using either the Facebook iOS SDK or a separate web view. Once login 51 | // is complete, you should refresh FacebookLikeView using -[FacebookLikeView load]. 52 | - (void)facebookLikeViewRequiresLogin:(FacebookLikeView *)aFacebookLikeView; 53 | 54 | @optional 55 | 56 | // Called when the web view finishes rendering its XFBML content 57 | - (void)facebookLikeViewDidRender:(FacebookLikeView *)aFacebookLikeView; 58 | 59 | // Called when the web view made a failed request or is redirected away from facebook.com 60 | - (void)facebookLikeView:(FacebookLikeView *)aFacebookLikeView didFailLoadWithError:(NSError *)error; 61 | 62 | // Called when the user likes a URL via this view 63 | - (void)facebookLikeViewDidLike:(FacebookLikeView *)aFacebookLikeView; 64 | 65 | // Called when the user unlikes a URL via this view 66 | - (void)facebookLikeViewDidUnlike:(FacebookLikeView *)aFacebookLikeView; 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /FacebookLikeView/Classes/FacebookLikeView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FacebookLikeView.m 3 | // Yardsellr 4 | // 5 | // Created by Tom Brow on 5/9/11. 6 | // Copyright 2011 Yardsellr. All rights reserved. 7 | // 8 | 9 | #import "FacebookLikeView.h" 10 | 11 | @interface FacebookLikeView () 12 | 13 | @property (strong, nonatomic) UIWebView *webView; 14 | 15 | @end 16 | 17 | @implementation NSData (UTF8String) 18 | 19 | - (NSString*)UTF8String { 20 | return [[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding]; 21 | } 22 | 23 | @end 24 | 25 | @implementation FacebookLikeView 26 | 27 | - (id)initWithFrame:(CGRect)frame { 28 | if (self = [super initWithFrame:frame]) { 29 | [self initCommon]; 30 | } 31 | return self; 32 | } 33 | 34 | - (id)initWithCoder:(NSCoder *)aDecoder { 35 | if (self = [super initWithCoder:aDecoder]) { 36 | [self initCommon]; 37 | } 38 | return self; 39 | } 40 | 41 | - (void)dealloc 42 | { 43 | // According to SDK doc, UIWebView's delegate must be set to nil before the view is released. 44 | self.webView.delegate = nil; 45 | 46 | } 47 | 48 | - (void)initCommon { 49 | self.webView = [[UIWebView alloc] init]; 50 | self.webView.opaque = NO; 51 | self.webView.backgroundColor = [UIColor clearColor]; 52 | self.webView.delegate = self; 53 | [self addSubview:self.webView]; 54 | 55 | // Prevent web view from scrolling 56 | for (UIScrollView *subview in self.webView.subviews) 57 | if ([subview isKindOfClass:[UIScrollView class]]) { 58 | subview.scrollEnabled = NO; 59 | subview.bounces = NO; 60 | } 61 | 62 | // Default settings 63 | self.href = [NSURL URLWithString:@"http://example.com"]; 64 | self.layout = @"standard"; 65 | self.showFaces = YES; 66 | self.action = @"like"; 67 | self.font = @"arial"; 68 | self.colorScheme = @"light"; 69 | self.ref = @""; 70 | } 71 | 72 | - (void)load { 73 | NSString *htmlFormat = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"FacebookLikeView" 74 | ofType:@"html"] 75 | encoding:NSUTF8StringEncoding 76 | error:nil]; 77 | NSString *html = [NSString stringWithFormat:htmlFormat, 78 | self.frame.size.width, 79 | self.href.absoluteString, 80 | self.layout, 81 | self.frame.size.width, 82 | self.showFaces ? @"true" : @"false", 83 | self.action, 84 | self.colorScheme, 85 | self.font, 86 | self.frame.size.height]; 87 | 88 | [self.webView loadHTMLString:html baseURL:self.href]; 89 | } 90 | 91 | - (void)didFailLoadWithError:(NSError *)error { 92 | if ([self.delegate respondsToSelector:@selector(facebookLikeView:didFailLoadWithError:)]) 93 | [self.delegate facebookLikeView:self didFailLoadWithError:error]; 94 | } 95 | 96 | - (void)didObserveFacebookEvent:(NSString *)fbEvent { 97 | if ([fbEvent isEqualToString:@"edge.create"] && [self.delegate respondsToSelector:@selector(facebookLikeViewDidLike:)]) 98 | [self.delegate facebookLikeViewDidLike:self]; 99 | else if ([fbEvent isEqualToString:@"edge.remove"] && [self.delegate respondsToSelector:@selector(facebookLikeViewDidUnlike:)]) 100 | [self.delegate facebookLikeViewDidUnlike:self]; 101 | else if ([fbEvent isEqualToString:@"xfbml.render"] && [self.delegate respondsToSelector:@selector(facebookLikeViewDidRender:)]) 102 | [self.delegate facebookLikeViewDidRender:self]; 103 | } 104 | 105 | #pragma mark UIWebViewDelegate 106 | 107 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 108 | // Allow loading Like button XFBML from file 109 | if ([request.URL.host isEqual:self.href.host]) 110 | return YES; 111 | 112 | // Allow loading about:blank, etc. 113 | if ([request.URL.scheme isEqualToString:@"about"]) 114 | return YES; 115 | 116 | // Block loading of 'event:*', our scheme for forwarding Facebook JS SDK events to native code 117 | else if ([request.URL.scheme isEqualToString:@"event"]) { 118 | [self didObserveFacebookEvent:request.URL.resourceSpecifier]; 119 | return NO; 120 | } 121 | 122 | // Block redirects to non-Facebook URLs (e.g., by public wifi access points) 123 | else if (![request.URL.host hasSuffix:@"facebook.com"] && ![request.URL.host hasSuffix:@"fbcdn.net"]) { 124 | NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys: 125 | @"FacebookLikeView was redirected to a non-Facebook URL.", NSLocalizedDescriptionKey, 126 | request.URL, NSURLErrorKey, 127 | nil]; 128 | NSError *error = [NSError errorWithDomain:@"FacebookLikeViewErrorDomain" 129 | code:0 130 | userInfo:errorInfo]; 131 | [self didFailLoadWithError:error]; 132 | return NO; 133 | } 134 | 135 | // Block redirects to the Facebook login page and notify the delegate that we've done so 136 | else if ([request.URL.path isEqualToString:@"/dialog/plugin.optin"] || 137 | ([request.URL.path isEqualToString:@"/plugins/like/connect"] && [request.HTTPBody.UTF8String hasPrefix:@"lsd"])) { 138 | [self.delegate facebookLikeViewRequiresLogin:self]; 139 | return NO; 140 | } 141 | 142 | else 143 | return YES; 144 | } 145 | 146 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 147 | [self didFailLoadWithError:error]; 148 | } 149 | 150 | #pragma mark UIView 151 | 152 | - (void)layoutSubviews { 153 | // Due to an apparent iOS 4 bug, layoutSubviews is sometimes called outside the main thread. 154 | // See https://devforums.apple.com/message/575760#575760 155 | if ([NSThread isMainThread]) 156 | self.webView.frame = self.bounds; 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /FacebookLikeView/Resources/FacebookLikeView.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 |
18 | 19 | 36 |
37 | 46 |
47 | 48 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D307EF6213BB98A6007D866B /* Facebook+ForceDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = D307EF6113BB98A6007D866B /* Facebook+ForceDialog.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 11 | D32BC59413B969FC0069C39F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D32BC59313B969FC0069C39F /* UIKit.framework */; }; 12 | D32BC59613B969FC0069C39F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D32BC59513B969FC0069C39F /* Foundation.framework */; }; 13 | D32BC59813B969FC0069C39F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D32BC59713B969FC0069C39F /* CoreGraphics.framework */; }; 14 | D32BC59E13B969FC0069C39F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D32BC59C13B969FC0069C39F /* InfoPlist.strings */; }; 15 | D32BC5A113B969FC0069C39F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5A013B969FC0069C39F /* main.m */; }; 16 | D32BC5A413B969FC0069C39F /* FacebookLikeViewDemoAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5A313B969FC0069C39F /* FacebookLikeViewDemoAppDelegate.m */; }; 17 | D32BC5A713B969FC0069C39F /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = D32BC5A513B969FC0069C39F /* MainWindow.xib */; }; 18 | D32BC5AA13B969FC0069C39F /* FacebookLikeViewDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5A913B969FC0069C39F /* FacebookLikeViewDemoViewController.m */; }; 19 | D32BC5AD13B969FC0069C39F /* FacebookLikeViewDemoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D32BC5AB13B969FC0069C39F /* FacebookLikeViewDemoViewController.xib */; }; 20 | D32BC5DA13B96AAA0069C39F /* FacebookLikeView.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5BE13B96AAA0069C39F /* FacebookLikeView.m */; }; 21 | D32BC5DB13B96AAA0069C39F /* FacebookLikeView.html in Resources */ = {isa = PBXBuildFile; fileRef = D32BC5C013B96AAA0069C39F /* FacebookLikeView.html */; }; 22 | D32BC5DC13B96AAA0069C39F /* Facebook.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5C313B96AAA0069C39F /* Facebook.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 23 | D32BC5DD13B96AAA0069C39F /* FBDialog.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D32BC5C513B96AAA0069C39F /* FBDialog.bundle */; }; 24 | D32BC5DE13B96AAA0069C39F /* FBDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5C713B96AAA0069C39F /* FBDialog.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 25 | D32BC5DF13B96AAA0069C39F /* FBLoginDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5C913B96AAA0069C39F /* FBLoginDialog.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 26 | D32BC5E013B96AAA0069C39F /* FBRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5CB13B96AAA0069C39F /* FBRequest.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 27 | D32BC5E113B96AAA0069C39F /* NSObject+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5CF13B96AAA0069C39F /* NSObject+SBJSON.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 28 | D32BC5E213B96AAA0069C39F /* NSString+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5D113B96AAA0069C39F /* NSString+SBJSON.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 29 | D32BC5E313B96AAA0069C39F /* SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5D313B96AAA0069C39F /* SBJSON.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 30 | D32BC5E413B96AAA0069C39F /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5D513B96AAA0069C39F /* SBJsonBase.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 31 | D32BC5E513B96AAA0069C39F /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5D713B96AAA0069C39F /* SBJsonParser.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 32 | D32BC5E613B96AAA0069C39F /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = D32BC5D913B96AAA0069C39F /* SBJsonWriter.m */; settings = {COMPILER_FLAGS = "-w -fno-objc-arc"; }; }; 33 | EA46D9B917EE4237001E32DC /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EA46D9B817EE4237001E32DC /* Default-568h@2x.png */; }; 34 | /* End PBXBuildFile section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | D307EF6113BB98A6007D866B /* Facebook+ForceDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Facebook+ForceDialog.m"; sourceTree = ""; }; 38 | D32BC58F13B969FC0069C39F /* FacebookLikeViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FacebookLikeViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | D32BC59313B969FC0069C39F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 40 | D32BC59513B969FC0069C39F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 41 | D32BC59713B969FC0069C39F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 42 | D32BC59B13B969FC0069C39F /* FacebookLikeViewDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FacebookLikeViewDemo-Info.plist"; sourceTree = ""; }; 43 | D32BC59D13B969FC0069C39F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 44 | D32BC59F13B969FC0069C39F /* FacebookLikeViewDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FacebookLikeViewDemo-Prefix.pch"; sourceTree = ""; }; 45 | D32BC5A013B969FC0069C39F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 46 | D32BC5A213B969FC0069C39F /* FacebookLikeViewDemoAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FacebookLikeViewDemoAppDelegate.h; sourceTree = ""; }; 47 | D32BC5A313B969FC0069C39F /* FacebookLikeViewDemoAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FacebookLikeViewDemoAppDelegate.m; sourceTree = ""; }; 48 | D32BC5A613B969FC0069C39F /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = ""; }; 49 | D32BC5A813B969FC0069C39F /* FacebookLikeViewDemoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FacebookLikeViewDemoViewController.h; sourceTree = ""; }; 50 | D32BC5A913B969FC0069C39F /* FacebookLikeViewDemoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FacebookLikeViewDemoViewController.m; sourceTree = ""; }; 51 | D32BC5AC13B969FC0069C39F /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/FacebookLikeViewDemoViewController.xib; sourceTree = ""; }; 52 | D32BC5BD13B96AAA0069C39F /* FacebookLikeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FacebookLikeView.h; sourceTree = ""; }; 53 | D32BC5BE13B96AAA0069C39F /* FacebookLikeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FacebookLikeView.m; sourceTree = ""; }; 54 | D32BC5C013B96AAA0069C39F /* FacebookLikeView.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = FacebookLikeView.html; sourceTree = ""; }; 55 | D32BC5C213B96AAA0069C39F /* Facebook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Facebook.h; sourceTree = ""; }; 56 | D32BC5C313B96AAA0069C39F /* Facebook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Facebook.m; sourceTree = ""; }; 57 | D32BC5C413B96AAA0069C39F /* FBConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnect.h; sourceTree = ""; }; 58 | D32BC5C513B96AAA0069C39F /* FBDialog.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FBDialog.bundle; sourceTree = ""; }; 59 | D32BC5C613B96AAA0069C39F /* FBDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBDialog.h; sourceTree = ""; }; 60 | D32BC5C713B96AAA0069C39F /* FBDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBDialog.m; sourceTree = ""; }; 61 | D32BC5C813B96AAA0069C39F /* FBLoginDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginDialog.h; sourceTree = ""; }; 62 | D32BC5C913B96AAA0069C39F /* FBLoginDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginDialog.m; sourceTree = ""; }; 63 | D32BC5CA13B96AAA0069C39F /* FBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBRequest.h; sourceTree = ""; }; 64 | D32BC5CB13B96AAA0069C39F /* FBRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRequest.m; sourceTree = ""; }; 65 | D32BC5CD13B96AAA0069C39F /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; 66 | D32BC5CE13B96AAA0069C39F /* NSObject+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJSON.h"; sourceTree = ""; }; 67 | D32BC5CF13B96AAA0069C39F /* NSObject+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJSON.m"; sourceTree = ""; }; 68 | D32BC5D013B96AAA0069C39F /* NSString+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SBJSON.h"; sourceTree = ""; }; 69 | D32BC5D113B96AAA0069C39F /* NSString+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SBJSON.m"; sourceTree = ""; }; 70 | D32BC5D213B96AAA0069C39F /* SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJSON.h; sourceTree = ""; }; 71 | D32BC5D313B96AAA0069C39F /* SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJSON.m; sourceTree = ""; }; 72 | D32BC5D413B96AAA0069C39F /* SBJsonBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonBase.h; sourceTree = ""; }; 73 | D32BC5D513B96AAA0069C39F /* SBJsonBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonBase.m; sourceTree = ""; }; 74 | D32BC5D613B96AAA0069C39F /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; 75 | D32BC5D713B96AAA0069C39F /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; 76 | D32BC5D813B96AAA0069C39F /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; 77 | D32BC5D913B96AAA0069C39F /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; 78 | EA46D9B817EE4237001E32DC /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 79 | /* End PBXFileReference section */ 80 | 81 | /* Begin PBXFrameworksBuildPhase section */ 82 | D32BC58C13B969FC0069C39F /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | D32BC59413B969FC0069C39F /* UIKit.framework in Frameworks */, 87 | D32BC59613B969FC0069C39F /* Foundation.framework in Frameworks */, 88 | D32BC59813B969FC0069C39F /* CoreGraphics.framework in Frameworks */, 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXFrameworksBuildPhase section */ 93 | 94 | /* Begin PBXGroup section */ 95 | D32BC58413B969FC0069C39F = { 96 | isa = PBXGroup; 97 | children = ( 98 | D32BC59913B969FC0069C39F /* FacebookLikeViewDemo */, 99 | D32BC59213B969FC0069C39F /* Frameworks */, 100 | D32BC59013B969FC0069C39F /* Products */, 101 | ); 102 | sourceTree = ""; 103 | }; 104 | D32BC59013B969FC0069C39F /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | D32BC58F13B969FC0069C39F /* FacebookLikeViewDemo.app */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | D32BC59213B969FC0069C39F /* Frameworks */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | D32BC59313B969FC0069C39F /* UIKit.framework */, 116 | D32BC59513B969FC0069C39F /* Foundation.framework */, 117 | D32BC59713B969FC0069C39F /* CoreGraphics.framework */, 118 | ); 119 | name = Frameworks; 120 | sourceTree = ""; 121 | }; 122 | D32BC59913B969FC0069C39F /* FacebookLikeViewDemo */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | D32BC5BB13B96AAA0069C39F /* FacebookLikeView */, 126 | D32BC5A213B969FC0069C39F /* FacebookLikeViewDemoAppDelegate.h */, 127 | D32BC5A313B969FC0069C39F /* FacebookLikeViewDemoAppDelegate.m */, 128 | D32BC5A813B969FC0069C39F /* FacebookLikeViewDemoViewController.h */, 129 | D32BC5A913B969FC0069C39F /* FacebookLikeViewDemoViewController.m */, 130 | D32BC5C113B96AAA0069C39F /* FBConnect */, 131 | EA46D9B717EE41BB001E32DC /* Resources */, 132 | D32BC59A13B969FC0069C39F /* Supporting Files */, 133 | ); 134 | path = FacebookLikeViewDemo; 135 | sourceTree = ""; 136 | }; 137 | D32BC59A13B969FC0069C39F /* Supporting Files */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | D32BC59B13B969FC0069C39F /* FacebookLikeViewDemo-Info.plist */, 141 | D32BC59C13B969FC0069C39F /* InfoPlist.strings */, 142 | D32BC59F13B969FC0069C39F /* FacebookLikeViewDemo-Prefix.pch */, 143 | D32BC5A013B969FC0069C39F /* main.m */, 144 | ); 145 | name = "Supporting Files"; 146 | sourceTree = ""; 147 | }; 148 | D32BC5BB13B96AAA0069C39F /* FacebookLikeView */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | D32BC5BC13B96AAA0069C39F /* Classes */, 152 | D32BC5BF13B96AAA0069C39F /* Resources */, 153 | ); 154 | path = FacebookLikeView; 155 | sourceTree = SOURCE_ROOT; 156 | }; 157 | D32BC5BC13B96AAA0069C39F /* Classes */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | D307EF6113BB98A6007D866B /* Facebook+ForceDialog.m */, 161 | D32BC5BD13B96AAA0069C39F /* FacebookLikeView.h */, 162 | D32BC5BE13B96AAA0069C39F /* FacebookLikeView.m */, 163 | ); 164 | path = Classes; 165 | sourceTree = ""; 166 | }; 167 | D32BC5BF13B96AAA0069C39F /* Resources */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | D32BC5C013B96AAA0069C39F /* FacebookLikeView.html */, 171 | ); 172 | path = Resources; 173 | sourceTree = ""; 174 | }; 175 | D32BC5C113B96AAA0069C39F /* FBConnect */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | D32BC5C213B96AAA0069C39F /* Facebook.h */, 179 | D32BC5C313B96AAA0069C39F /* Facebook.m */, 180 | D32BC5C413B96AAA0069C39F /* FBConnect.h */, 181 | D32BC5C513B96AAA0069C39F /* FBDialog.bundle */, 182 | D32BC5C613B96AAA0069C39F /* FBDialog.h */, 183 | D32BC5C713B96AAA0069C39F /* FBDialog.m */, 184 | D32BC5C813B96AAA0069C39F /* FBLoginDialog.h */, 185 | D32BC5C913B96AAA0069C39F /* FBLoginDialog.m */, 186 | D32BC5CA13B96AAA0069C39F /* FBRequest.h */, 187 | D32BC5CB13B96AAA0069C39F /* FBRequest.m */, 188 | D32BC5CC13B96AAA0069C39F /* JSON */, 189 | ); 190 | path = FBConnect; 191 | sourceTree = SOURCE_ROOT; 192 | }; 193 | D32BC5CC13B96AAA0069C39F /* JSON */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | D32BC5CD13B96AAA0069C39F /* JSON.h */, 197 | D32BC5CE13B96AAA0069C39F /* NSObject+SBJSON.h */, 198 | D32BC5CF13B96AAA0069C39F /* NSObject+SBJSON.m */, 199 | D32BC5D013B96AAA0069C39F /* NSString+SBJSON.h */, 200 | D32BC5D113B96AAA0069C39F /* NSString+SBJSON.m */, 201 | D32BC5D213B96AAA0069C39F /* SBJSON.h */, 202 | D32BC5D313B96AAA0069C39F /* SBJSON.m */, 203 | D32BC5D413B96AAA0069C39F /* SBJsonBase.h */, 204 | D32BC5D513B96AAA0069C39F /* SBJsonBase.m */, 205 | D32BC5D613B96AAA0069C39F /* SBJsonParser.h */, 206 | D32BC5D713B96AAA0069C39F /* SBJsonParser.m */, 207 | D32BC5D813B96AAA0069C39F /* SBJsonWriter.h */, 208 | D32BC5D913B96AAA0069C39F /* SBJsonWriter.m */, 209 | ); 210 | path = JSON; 211 | sourceTree = ""; 212 | }; 213 | EA46D9B717EE41BB001E32DC /* Resources */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | EA46D9B817EE4237001E32DC /* Default-568h@2x.png */, 217 | D32BC5AB13B969FC0069C39F /* FacebookLikeViewDemoViewController.xib */, 218 | D32BC5A513B969FC0069C39F /* MainWindow.xib */, 219 | ); 220 | name = Resources; 221 | sourceTree = ""; 222 | }; 223 | /* End PBXGroup section */ 224 | 225 | /* Begin PBXNativeTarget section */ 226 | D32BC58E13B969FC0069C39F /* FacebookLikeViewDemo */ = { 227 | isa = PBXNativeTarget; 228 | buildConfigurationList = D32BC5B013B969FC0069C39F /* Build configuration list for PBXNativeTarget "FacebookLikeViewDemo" */; 229 | buildPhases = ( 230 | D32BC58B13B969FC0069C39F /* Sources */, 231 | D32BC58C13B969FC0069C39F /* Frameworks */, 232 | D32BC58D13B969FC0069C39F /* Resources */, 233 | ); 234 | buildRules = ( 235 | ); 236 | dependencies = ( 237 | ); 238 | name = FacebookLikeViewDemo; 239 | productName = FacebookLikeViewDemo; 240 | productReference = D32BC58F13B969FC0069C39F /* FacebookLikeViewDemo.app */; 241 | productType = "com.apple.product-type.application"; 242 | }; 243 | /* End PBXNativeTarget section */ 244 | 245 | /* Begin PBXProject section */ 246 | D32BC58613B969FC0069C39F /* Project object */ = { 247 | isa = PBXProject; 248 | attributes = { 249 | LastUpgradeCheck = 0500; 250 | ORGANIZATIONNAME = "Tom Brow"; 251 | }; 252 | buildConfigurationList = D32BC58913B969FC0069C39F /* Build configuration list for PBXProject "FacebookLikeViewDemo" */; 253 | compatibilityVersion = "Xcode 3.2"; 254 | developmentRegion = English; 255 | hasScannedForEncodings = 0; 256 | knownRegions = ( 257 | en, 258 | ); 259 | mainGroup = D32BC58413B969FC0069C39F; 260 | productRefGroup = D32BC59013B969FC0069C39F /* Products */; 261 | projectDirPath = ""; 262 | projectRoot = ""; 263 | targets = ( 264 | D32BC58E13B969FC0069C39F /* FacebookLikeViewDemo */, 265 | ); 266 | }; 267 | /* End PBXProject section */ 268 | 269 | /* Begin PBXResourcesBuildPhase section */ 270 | D32BC58D13B969FC0069C39F /* Resources */ = { 271 | isa = PBXResourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | D32BC59E13B969FC0069C39F /* InfoPlist.strings in Resources */, 275 | D32BC5A713B969FC0069C39F /* MainWindow.xib in Resources */, 276 | D32BC5AD13B969FC0069C39F /* FacebookLikeViewDemoViewController.xib in Resources */, 277 | D32BC5DB13B96AAA0069C39F /* FacebookLikeView.html in Resources */, 278 | D32BC5DD13B96AAA0069C39F /* FBDialog.bundle in Resources */, 279 | EA46D9B917EE4237001E32DC /* Default-568h@2x.png in Resources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | /* End PBXResourcesBuildPhase section */ 284 | 285 | /* Begin PBXSourcesBuildPhase section */ 286 | D32BC58B13B969FC0069C39F /* Sources */ = { 287 | isa = PBXSourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | D32BC5A113B969FC0069C39F /* main.m in Sources */, 291 | D32BC5A413B969FC0069C39F /* FacebookLikeViewDemoAppDelegate.m in Sources */, 292 | D32BC5AA13B969FC0069C39F /* FacebookLikeViewDemoViewController.m in Sources */, 293 | D32BC5DA13B96AAA0069C39F /* FacebookLikeView.m in Sources */, 294 | D32BC5DC13B96AAA0069C39F /* Facebook.m in Sources */, 295 | D32BC5DE13B96AAA0069C39F /* FBDialog.m in Sources */, 296 | D32BC5DF13B96AAA0069C39F /* FBLoginDialog.m in Sources */, 297 | D32BC5E013B96AAA0069C39F /* FBRequest.m in Sources */, 298 | D32BC5E113B96AAA0069C39F /* NSObject+SBJSON.m in Sources */, 299 | D32BC5E213B96AAA0069C39F /* NSString+SBJSON.m in Sources */, 300 | D32BC5E313B96AAA0069C39F /* SBJSON.m in Sources */, 301 | D32BC5E413B96AAA0069C39F /* SBJsonBase.m in Sources */, 302 | D32BC5E513B96AAA0069C39F /* SBJsonParser.m in Sources */, 303 | D32BC5E613B96AAA0069C39F /* SBJsonWriter.m in Sources */, 304 | D307EF6213BB98A6007D866B /* Facebook+ForceDialog.m in Sources */, 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | /* End PBXSourcesBuildPhase section */ 309 | 310 | /* Begin PBXVariantGroup section */ 311 | D32BC59C13B969FC0069C39F /* InfoPlist.strings */ = { 312 | isa = PBXVariantGroup; 313 | children = ( 314 | D32BC59D13B969FC0069C39F /* en */, 315 | ); 316 | name = InfoPlist.strings; 317 | sourceTree = ""; 318 | }; 319 | D32BC5A513B969FC0069C39F /* MainWindow.xib */ = { 320 | isa = PBXVariantGroup; 321 | children = ( 322 | D32BC5A613B969FC0069C39F /* en */, 323 | ); 324 | name = MainWindow.xib; 325 | sourceTree = ""; 326 | }; 327 | D32BC5AB13B969FC0069C39F /* FacebookLikeViewDemoViewController.xib */ = { 328 | isa = PBXVariantGroup; 329 | children = ( 330 | D32BC5AC13B969FC0069C39F /* en */, 331 | ); 332 | name = FacebookLikeViewDemoViewController.xib; 333 | sourceTree = ""; 334 | }; 335 | /* End PBXVariantGroup section */ 336 | 337 | /* Begin XCBuildConfiguration section */ 338 | D32BC5AE13B969FC0069C39F /* Debug */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 342 | GCC_C_LANGUAGE_STANDARD = gnu99; 343 | GCC_OPTIMIZATION_LEVEL = 0; 344 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG; 345 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 346 | GCC_VERSION = com.apple.compilers.llvmgcc42; 347 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 350 | ONLY_ACTIVE_ARCH = YES; 351 | SDKROOT = iphoneos; 352 | }; 353 | name = Debug; 354 | }; 355 | D32BC5AF13B969FC0069C39F /* Release */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 359 | GCC_C_LANGUAGE_STANDARD = gnu99; 360 | GCC_VERSION = com.apple.compilers.llvmgcc42; 361 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 362 | GCC_WARN_UNUSED_VARIABLE = YES; 363 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 364 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 365 | SDKROOT = iphoneos; 366 | }; 367 | name = Release; 368 | }; 369 | D32BC5B113B969FC0069C39F /* Debug */ = { 370 | isa = XCBuildConfiguration; 371 | buildSettings = { 372 | ALWAYS_SEARCH_USER_PATHS = NO; 373 | CLANG_ENABLE_OBJC_ARC = YES; 374 | COPY_PHASE_STRIP = NO; 375 | GCC_DYNAMIC_NO_PIC = NO; 376 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 377 | GCC_PREFIX_HEADER = "FacebookLikeViewDemo/FacebookLikeViewDemo-Prefix.pch"; 378 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 379 | INFOPLIST_FILE = "FacebookLikeViewDemo/FacebookLikeViewDemo-Info.plist"; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | WRAPPER_EXTENSION = app; 382 | }; 383 | name = Debug; 384 | }; 385 | D32BC5B213B969FC0069C39F /* Release */ = { 386 | isa = XCBuildConfiguration; 387 | buildSettings = { 388 | ALWAYS_SEARCH_USER_PATHS = NO; 389 | CLANG_ENABLE_OBJC_ARC = YES; 390 | COPY_PHASE_STRIP = YES; 391 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 392 | GCC_PREFIX_HEADER = "FacebookLikeViewDemo/FacebookLikeViewDemo-Prefix.pch"; 393 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 394 | INFOPLIST_FILE = "FacebookLikeViewDemo/FacebookLikeViewDemo-Info.plist"; 395 | PRODUCT_NAME = "$(TARGET_NAME)"; 396 | VALIDATE_PRODUCT = YES; 397 | WRAPPER_EXTENSION = app; 398 | }; 399 | name = Release; 400 | }; 401 | /* End XCBuildConfiguration section */ 402 | 403 | /* Begin XCConfigurationList section */ 404 | D32BC58913B969FC0069C39F /* Build configuration list for PBXProject "FacebookLikeViewDemo" */ = { 405 | isa = XCConfigurationList; 406 | buildConfigurations = ( 407 | D32BC5AE13B969FC0069C39F /* Debug */, 408 | D32BC5AF13B969FC0069C39F /* Release */, 409 | ); 410 | defaultConfigurationIsVisible = 0; 411 | defaultConfigurationName = Release; 412 | }; 413 | D32BC5B013B969FC0069C39F /* Build configuration list for PBXNativeTarget "FacebookLikeViewDemo" */ = { 414 | isa = XCConfigurationList; 415 | buildConfigurations = ( 416 | D32BC5B113B969FC0069C39F /* Debug */, 417 | D32BC5B213B969FC0069C39F /* Release */, 418 | ); 419 | defaultConfigurationIsVisible = 0; 420 | defaultConfigurationName = Release; 421 | }; 422 | /* End XCConfigurationList section */ 423 | }; 424 | rootObject = D32BC58613B969FC0069C39F /* Project object */; 425 | } 426 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/FacebookLikeView/da914d9c9ef0306b2a2a888e3b2d71e26f22dd3b/FacebookLikeViewDemo/Default-568h@2x.png -------------------------------------------------------------------------------- /FacebookLikeViewDemo/FacebookLikeViewDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Like Demo 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.yardsellr.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | NSMainNibFile 30 | MainWindow 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/FacebookLikeViewDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'FacebookLikeViewDemo' target in the 'FacebookLikeViewDemo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iPhone SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/FacebookLikeViewDemoAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // LikeButtonDemoAppDelegate.h 3 | // LikeButtonDemo 4 | // 5 | // Created by Tom Brow on 6/27/11. 6 | // Copyright 2011 Yardsellr. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FacebookLikeViewDemoViewController; 12 | 13 | @interface FacebookLikeViewDemoAppDelegate : NSObject 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/FacebookLikeViewDemoAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // LikeButtonDemoAppDelegate.m 3 | // LikeButtonDemo 4 | // 5 | // Created by Tom Brow on 6/27/11. 6 | // Copyright 2011 Yardsellr. All rights reserved. 7 | // 8 | 9 | #import "FacebookLikeViewDemoAppDelegate.h" 10 | #import "FacebookLikeViewDemoViewController.h" 11 | 12 | #define SavedHTTPCookiesKey @"SavedHTTPCookies" 13 | 14 | @interface FacebookLikeViewDemoAppDelegate () 15 | 16 | @property (nonatomic, strong) IBOutlet FacebookLikeViewDemoViewController *viewController; 17 | 18 | @end 19 | 20 | @implementation FacebookLikeViewDemoAppDelegate 21 | 22 | @synthesize window=_window; 23 | 24 | @synthesize viewController=_viewController; 25 | 26 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 27 | { 28 | //Restore cookies 29 | NSData *cookiesData = [[NSUserDefaults standardUserDefaults] objectForKey:SavedHTTPCookiesKey]; 30 | if (cookiesData) { 31 | NSArray *cookies = [NSKeyedUnarchiver unarchiveObjectWithData:cookiesData]; 32 | for (NSHTTPCookie *cookie in cookies) 33 | [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie]; 34 | } 35 | 36 | self.window.rootViewController = self.viewController; 37 | [self.window makeKeyAndVisible]; 38 | return YES; 39 | } 40 | 41 | - (void)applicationDidEnterBackground:(UIApplication *)application { 42 | // Save cookies 43 | NSData *cookiesData = [NSKeyedArchiver archivedDataWithRootObject:[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]]; 44 | [[NSUserDefaults standardUserDefaults] setObject:cookiesData 45 | forKey:SavedHTTPCookiesKey]; 46 | } 47 | 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/FacebookLikeViewDemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LikeButtonDemoViewController.h 3 | // LikeButtonDemo 4 | // 5 | // Created by Tom Brow on 6/27/11. 6 | // Copyright 2011 Yardsellr. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FacebookLikeViewDemoViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/FacebookLikeViewDemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LikeButtonDemoViewController.m 3 | // LikeButtonDemo 4 | // 5 | // Created by Tom Brow on 6/27/11. 6 | // Copyright 2011 Yardsellr. All rights reserved. 7 | // 8 | 9 | #import "FacebookLikeViewDemoViewController.h" 10 | #import "FBConnect.h" 11 | #import "FacebookLikeView.h" 12 | 13 | @interface FacebookLikeViewDemoViewController () 14 | 15 | @property (nonatomic, strong) Facebook *facebook; 16 | @property (nonatomic, strong) IBOutlet FacebookLikeView *facebookLikeView; 17 | 18 | @end 19 | 20 | @implementation FacebookLikeViewDemoViewController 21 | 22 | - (id)initWithCoder:(NSCoder *)aDecoder { 23 | if (self = [super initWithCoder:aDecoder]) { 24 | self.facebook = [[Facebook alloc] initWithAppId:@"158575400878173" andDelegate:self]; 25 | } 26 | return self; 27 | } 28 | 29 | 30 | #pragma mark FBSessionDelegate 31 | 32 | - (void)fbDidLogin { 33 | self.facebookLikeView.alpha = 1; 34 | [self.facebookLikeView load]; 35 | } 36 | 37 | - (void)fbDidLogout { 38 | self.facebookLikeView.alpha = 1; 39 | [self.facebookLikeView load]; 40 | } 41 | 42 | #pragma mark FacebookLikeViewDelegate 43 | 44 | - (void)facebookLikeViewRequiresLogin:(FacebookLikeView *)aFacebookLikeView { 45 | [self.facebook authorize:[NSArray array]]; 46 | } 47 | 48 | - (void)facebookLikeViewDidRender:(FacebookLikeView *)aFacebookLikeView { 49 | [UIView beginAnimations:@"" context:nil]; 50 | [UIView setAnimationDelay:0.5]; 51 | self.facebookLikeView.alpha = 1; 52 | [UIView commitAnimations]; 53 | } 54 | 55 | - (void)facebookLikeViewDidLike:(FacebookLikeView *)aFacebookLikeView { 56 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Liked" 57 | message:@"You liked Yardsellr. Thanks!" 58 | delegate:self 59 | cancelButtonTitle:@"OK" 60 | otherButtonTitles:nil]; 61 | [alert show]; 62 | } 63 | 64 | - (void)facebookLikeViewDidUnlike:(FacebookLikeView *)aFacebookLikeView { 65 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unliked" 66 | message:@"You unliked Yardsellr. Where's the love?" 67 | delegate:self 68 | cancelButtonTitle:@"OK" 69 | otherButtonTitles:nil]; 70 | [alert show]; 71 | } 72 | 73 | #pragma mark UIViewController 74 | 75 | - (void)viewDidLoad 76 | { 77 | [super viewDidLoad]; 78 | 79 | self.facebookLikeView.href = [NSURL URLWithString:@"http://www.yardsellr.com"]; 80 | self.facebookLikeView.layout = @"button_count"; 81 | self.facebookLikeView.showFaces = NO; 82 | self.facebookLikeView.alpha = 0; 83 | [self.facebookLikeView load]; 84 | } 85 | 86 | - (void)viewDidUnload 87 | { 88 | [super viewDidUnload]; 89 | 90 | self.facebookLikeView = nil; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/LikeButtonDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleURLTypes 8 | 9 | 10 | CFBundleURLSchemes 11 | 12 | fb158575400878173 13 | 14 | CFBundleURLName 15 | 16 | 17 | 18 | CFBundleDisplayName 19 | ${PRODUCT_NAME} 20 | CFBundleExecutable 21 | ${EXECUTABLE_NAME} 22 | CFBundleIconFile 23 | 24 | CFBundleIdentifier 25 | com.yardsellr.${PRODUCT_NAME:rfc1034identifier} 26 | CFBundleInfoDictionaryVersion 27 | 6.0 28 | CFBundleName 29 | ${PRODUCT_NAME} 30 | CFBundlePackageType 31 | APPL 32 | CFBundleShortVersionString 33 | 1.0 34 | CFBundleSignature 35 | ???? 36 | CFBundleVersion 37 | 1.0 38 | LSRequiresIPhoneOS 39 | 40 | NSMainNibFile 41 | MainWindow 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/LikeButtonDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'LikeButtonDemo' target in the 'LikeButtonDemo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iPhone SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/en.lproj/FacebookLikeViewDemoViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1536 5 | 11G63 6 | 2840 7 | 1138.51 8 | 569.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1926 12 | 13 | 14 | YES 15 | IBProxyObject 16 | IBUILabel 17 | IBUIView 18 | 19 | 20 | YES 21 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 22 | 23 | 24 | PluginDependencyRecalculationVersion 25 | 26 | 27 | 28 | YES 29 | 30 | IBFilesOwner 31 | IBCocoaTouchFramework 32 | 33 | 34 | IBFirstResponder 35 | IBCocoaTouchFramework 36 | 37 | 38 | 39 | 274 40 | 41 | YES 42 | 43 | 44 | 292 45 | {{136, 189}, {48, 21}} 46 | 47 | 48 | 49 | 50 | 3 51 | MCAwAA 52 | 53 | IBCocoaTouchFramework 54 | 55 | 56 | 57 | 292 58 | {{14, 155}, {293, 21}} 59 | 60 | 61 | 62 | NO 63 | YES 64 | 7 65 | NO 66 | IBCocoaTouchFramework 67 | Like button appears here: 68 | 69 | 3 70 | MC4zMzMzMzMzMzMzAA 71 | 72 | 73 | 1 74 | 1 75 | 76 | Helvetica 77 | Helvetica 78 | 0 79 | 17 80 | 81 | 82 | Helvetica 83 | 17 84 | 16 85 | 86 | NO 87 | 88 | 89 | 90 | 292 91 | {{0, 220}, {320, 21}} 92 | 93 | 94 | 95 | 96 | NO 97 | YES 98 | 7 99 | NO 100 | IBCocoaTouchFramework 101 | (Check your net connection if it doesn't.) 102 | 103 | 3 104 | MC41AA 105 | 106 | 107 | 1 108 | 1 109 | 110 | Helvetica 111 | Helvetica 112 | 0 113 | 14 114 | 115 | 116 | Helvetica 117 | 14 118 | 16 119 | 120 | NO 121 | 122 | 123 | 124 | 292 125 | {{61, 188}, {66, 21}} 126 | 127 | 128 | 129 | NO 130 | YES 131 | 7 132 | NO 133 | IBCocoaTouchFramework 134 | ------> 135 | 136 | 137 | 1 138 | 1 139 | 140 | 141 | NO 142 | 143 | 144 | 145 | 292 146 | {{192, 188}, {66, 21}} 147 | 148 | 149 | 150 | NO 151 | YES 152 | 7 153 | NO 154 | IBCocoaTouchFramework 155 | <------ 156 | 157 | 158 | 1 159 | 1 160 | 161 | 162 | NO 163 | 164 | 165 | {{0, 20}, {320, 460}} 166 | 167 | 168 | 169 | 170 | 3 171 | MQA 172 | 173 | 2 174 | 175 | 176 | NO 177 | 178 | IBCocoaTouchFramework 179 | 180 | 181 | 182 | 183 | YES 184 | 185 | 186 | view 187 | 188 | 189 | 190 | 7 191 | 192 | 193 | 194 | facebookLikeView 195 | 196 | 197 | 198 | 9 199 | 200 | 201 | 202 | delegate 203 | 204 | 205 | 206 | 10 207 | 208 | 209 | 210 | 211 | YES 212 | 213 | 0 214 | 215 | YES 216 | 217 | 218 | 219 | 220 | 221 | -1 222 | 223 | 224 | File's Owner 225 | 226 | 227 | -2 228 | 229 | 230 | 231 | 232 | 6 233 | 234 | 235 | YES 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 8 246 | 247 | 248 | YES 249 | 250 | 251 | Facebook Like View 252 | 253 | 254 | 11 255 | 256 | 257 | 258 | 259 | 12 260 | 261 | 262 | 263 | 264 | 14 265 | 266 | 267 | 268 | 269 | 15 270 | 271 | 272 | 273 | 274 | 275 | 276 | YES 277 | 278 | YES 279 | -1.CustomClassName 280 | -1.IBPluginDependency 281 | -2.CustomClassName 282 | -2.IBPluginDependency 283 | 11.IBPluginDependency 284 | 12.IBPluginDependency 285 | 14.IBPluginDependency 286 | 15.IBPluginDependency 287 | 6.IBPluginDependency 288 | 8.CustomClassName 289 | 8.IBPluginDependency 290 | 291 | 292 | YES 293 | FacebookLikeViewDemoViewController 294 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 295 | UIResponder 296 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 297 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 298 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 299 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 300 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 301 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 302 | FacebookLikeView 303 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 304 | 305 | 306 | 307 | YES 308 | 309 | 310 | 311 | 312 | 313 | YES 314 | 315 | 316 | 317 | 318 | 15 319 | 320 | 321 | 322 | YES 323 | 324 | FacebookLikeView 325 | UIView 326 | 327 | delegate 328 | id 329 | 330 | 331 | delegate 332 | 333 | delegate 334 | id 335 | 336 | 337 | 338 | IBProjectSource 339 | ./Classes/FacebookLikeView.h 340 | 341 | 342 | 343 | FacebookLikeViewDemoViewController 344 | UIViewController 345 | 346 | facebookLikeView 347 | FacebookLikeView 348 | 349 | 350 | facebookLikeView 351 | 352 | facebookLikeView 353 | FacebookLikeView 354 | 355 | 356 | 357 | IBProjectSource 358 | ./Classes/FacebookLikeViewDemoViewController.h 359 | 360 | 361 | 362 | 363 | 0 364 | IBCocoaTouchFramework 365 | 366 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 367 | 368 | 369 | YES 370 | 3 371 | 1926 372 | 373 | 374 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/en.lproj/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10D571 6 | 786 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 112 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | IBCocoaTouchFramework 42 | 43 | 44 | FacebookLikeViewDemoViewController 45 | 46 | 47 | 1 48 | 49 | IBCocoaTouchFramework 50 | NO 51 | 52 | 53 | 54 | 292 55 | {320, 480} 56 | 57 | 1 58 | MSAxIDEAA 59 | 60 | NO 61 | NO 62 | 63 | IBCocoaTouchFramework 64 | YES 65 | 66 | 67 | 68 | 69 | YES 70 | 71 | 72 | delegate 73 | 74 | 75 | 76 | 4 77 | 78 | 79 | 80 | viewController 81 | 82 | 83 | 84 | 11 85 | 86 | 87 | 88 | window 89 | 90 | 91 | 92 | 14 93 | 94 | 95 | 96 | 97 | YES 98 | 99 | 0 100 | 101 | 102 | 103 | 104 | 105 | -1 106 | 107 | 108 | File's Owner 109 | 110 | 111 | 3 112 | 113 | 114 | FacebookLikeViewDemo App Delegate 115 | 116 | 117 | -2 118 | 119 | 120 | 121 | 122 | 10 123 | 124 | 125 | 126 | 127 | 12 128 | 129 | 130 | 131 | 132 | 133 | 134 | YES 135 | 136 | YES 137 | -1.CustomClassName 138 | -2.CustomClassName 139 | 10.CustomClassName 140 | 10.IBEditorWindowLastContentRect 141 | 10.IBPluginDependency 142 | 12.IBEditorWindowLastContentRect 143 | 12.IBPluginDependency 144 | 3.CustomClassName 145 | 3.IBPluginDependency 146 | 147 | 148 | YES 149 | UIApplication 150 | UIResponder 151 | FacebookLikeViewDemoViewController 152 | {{234, 376}, {320, 480}} 153 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 154 | {{525, 346}, {320, 480}} 155 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 156 | FacebookLikeViewDemoAppDelegate 157 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 158 | 159 | 160 | 161 | YES 162 | 163 | 164 | YES 165 | 166 | 167 | 168 | 169 | YES 170 | 171 | 172 | YES 173 | 174 | 175 | 176 | 15 177 | 178 | 179 | 180 | YES 181 | 182 | UIWindow 183 | UIView 184 | 185 | IBUserSource 186 | 187 | 188 | 189 | 190 | FacebookLikeViewDemoAppDelegate 191 | NSObject 192 | 193 | YES 194 | 195 | YES 196 | viewController 197 | window 198 | 199 | 200 | YES 201 | FacebookLikeViewDemoViewController 202 | UIWindow 203 | 204 | 205 | 206 | YES 207 | 208 | YES 209 | viewController 210 | window 211 | 212 | 213 | YES 214 | 215 | viewController 216 | FacebookLikeViewDemoViewController 217 | 218 | 219 | window 220 | UIWindow 221 | 222 | 223 | 224 | 225 | IBProjectSource 226 | FacebookLikeViewDemoAppDelegate.h 227 | 228 | 229 | 230 | FacebookLikeViewDemoAppDelegate 231 | NSObject 232 | 233 | IBUserSource 234 | 235 | 236 | 237 | 238 | FacebookLikeViewDemoViewController 239 | UIViewController 240 | 241 | IBProjectSource 242 | FacebookLikeViewDemoViewController.h 243 | 244 | 245 | 246 | 247 | YES 248 | 249 | NSObject 250 | 251 | IBFrameworkSource 252 | Foundation.framework/Headers/NSError.h 253 | 254 | 255 | 256 | NSObject 257 | 258 | IBFrameworkSource 259 | Foundation.framework/Headers/NSFileManager.h 260 | 261 | 262 | 263 | NSObject 264 | 265 | IBFrameworkSource 266 | Foundation.framework/Headers/NSKeyValueCoding.h 267 | 268 | 269 | 270 | NSObject 271 | 272 | IBFrameworkSource 273 | Foundation.framework/Headers/NSKeyValueObserving.h 274 | 275 | 276 | 277 | NSObject 278 | 279 | IBFrameworkSource 280 | Foundation.framework/Headers/NSKeyedArchiver.h 281 | 282 | 283 | 284 | NSObject 285 | 286 | IBFrameworkSource 287 | Foundation.framework/Headers/NSObject.h 288 | 289 | 290 | 291 | NSObject 292 | 293 | IBFrameworkSource 294 | Foundation.framework/Headers/NSRunLoop.h 295 | 296 | 297 | 298 | NSObject 299 | 300 | IBFrameworkSource 301 | Foundation.framework/Headers/NSThread.h 302 | 303 | 304 | 305 | NSObject 306 | 307 | IBFrameworkSource 308 | Foundation.framework/Headers/NSURL.h 309 | 310 | 311 | 312 | NSObject 313 | 314 | IBFrameworkSource 315 | Foundation.framework/Headers/NSURLConnection.h 316 | 317 | 318 | 319 | NSObject 320 | 321 | IBFrameworkSource 322 | UIKit.framework/Headers/UIAccessibility.h 323 | 324 | 325 | 326 | NSObject 327 | 328 | IBFrameworkSource 329 | UIKit.framework/Headers/UINibLoading.h 330 | 331 | 332 | 333 | NSObject 334 | 335 | IBFrameworkSource 336 | UIKit.framework/Headers/UIResponder.h 337 | 338 | 339 | 340 | UIApplication 341 | UIResponder 342 | 343 | IBFrameworkSource 344 | UIKit.framework/Headers/UIApplication.h 345 | 346 | 347 | 348 | UIResponder 349 | NSObject 350 | 351 | 352 | 353 | UISearchBar 354 | UIView 355 | 356 | IBFrameworkSource 357 | UIKit.framework/Headers/UISearchBar.h 358 | 359 | 360 | 361 | UISearchDisplayController 362 | NSObject 363 | 364 | IBFrameworkSource 365 | UIKit.framework/Headers/UISearchDisplayController.h 366 | 367 | 368 | 369 | UIView 370 | 371 | IBFrameworkSource 372 | UIKit.framework/Headers/UITextField.h 373 | 374 | 375 | 376 | UIView 377 | UIResponder 378 | 379 | IBFrameworkSource 380 | UIKit.framework/Headers/UIView.h 381 | 382 | 383 | 384 | UIViewController 385 | 386 | IBFrameworkSource 387 | UIKit.framework/Headers/UINavigationController.h 388 | 389 | 390 | 391 | UIViewController 392 | 393 | IBFrameworkSource 394 | UIKit.framework/Headers/UIPopoverController.h 395 | 396 | 397 | 398 | UIViewController 399 | 400 | IBFrameworkSource 401 | UIKit.framework/Headers/UISplitViewController.h 402 | 403 | 404 | 405 | UIViewController 406 | 407 | IBFrameworkSource 408 | UIKit.framework/Headers/UITabBarController.h 409 | 410 | 411 | 412 | UIViewController 413 | UIResponder 414 | 415 | IBFrameworkSource 416 | UIKit.framework/Headers/UIViewController.h 417 | 418 | 419 | 420 | UIWindow 421 | UIView 422 | 423 | IBFrameworkSource 424 | UIKit.framework/Headers/UIWindow.h 425 | 426 | 427 | 428 | 429 | 0 430 | IBCocoaTouchFramework 431 | 432 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 433 | 434 | 435 | 436 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 437 | 438 | 439 | YES 440 | FacebookLikeViewDemo.xcodeproj 441 | 3 442 | 112 443 | 444 | 445 | -------------------------------------------------------------------------------- /FacebookLikeViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LikeButtonDemo 4 | // 5 | // Created by Tom Brow on 6/27/11. 6 | // Copyright 2011 Yardsellr. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | @autoreleasepool { 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | return retVal; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2011 Yardsellr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub-license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice, and every other copyright notice found in this software, and all the attributions in every file, and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #FacebookLikeView 2 | 3 | FacebookLikeView is a Facebook Like button for native iOS apps. 4 | 5 | It integrates with the Facebook iOS SDK so that authenticated users can Like 6 | with a single tap, and unauthenticated users are prompted with the standard 7 | authentication dialog. 8 | 9 | FacebookLikeView is not officially supported by Facebook, and it requires your 10 | application to use the in-app authentication dialog rather than single sign-on 11 | via Safari or the Facebook app. 12 | 13 | To see FacebookLikeView in action, build the included `FacebookLikeViewDemo` 14 | project. 15 | 16 | ##Getting started 17 | 18 | 1. If you haven't already installed the Facebook iOS SDK, add the files in the 19 | `FBConnect` directory to your Xcode project. 20 | 2. Add the files in the `FacebookLikeView` directory to your Xcode project. 21 | 3. Instantiate a FacebookLikeView programmatically or in a nib. 22 | 4. Set the URL to be liked, plus any [Like button attributes] you'd like to 23 | customize. Make sure the `layout` you choose fits within the view's bounds. 24 | 25 | _facebookLikeView.href = [NSURL URLWithString:@"http://www.yardsellr.com"]; 26 | _facebookLikeView.layout = @"button_count"; 27 | _facebookLikeView.showFaces = NO; 28 | 29 | 5. Set a delegate that implements `facebookLikeViewRequiresLogin:`. Your 30 | implementation should call `-[Facebook authorize:delegate:]`, and then 31 | `-[FacebookLikeView load]` once login is complete. 32 | 33 | _facebookLikeView.delegate = self; 34 | 35 | ... 36 | 37 | - (void)facebookLikeViewRequiresLogin:(FacebookLikeView *)aFacebookLikeView { 38 | [_facebook authorize:[NSArray array] delegate:self]; 39 | } 40 | 41 | - (void)fbDidLogin { 42 | [_facebookLikeView load]; 43 | } 44 | 45 | 6. Finally, call `-[FacebookLikeView load]` before you display the view. You 46 | should also call this method any time the user signs in or out of Facebook, 47 | and after modifying any of the FacebookLikeView's properties. 48 | 49 | ##More delegate methods 50 | 51 | You may want to be notified when the Like button is used. In that case, 52 | implement these optional FacebookLikeViewDelegate methods: 53 | 54 | - (void)facebookLikeViewDidLike:(FacebookLikeView *)aFacebookLikeView; 55 | - (void)facebookLikeViewDidUnlike:(FacebookLikeView *)aFacebookLikeView; 56 | 57 | To avoid showing the Like button before it's completely rendered, you can hide 58 | the FacebookLikeView until this delegate method is called: 59 | 60 | - (void)facebookLikeViewDidRender:(FacebookLikeView *)aFacebookLikeView; 61 | 62 | ##How it works 63 | 64 | FacebookLikeView uses a web view to host the same Like button XFBML as would be 65 | used on a web page. 66 | 67 | Since the web view shares cookies with all other web views in your app, a user 68 | that authenticates through Facebook's in-app dialog is also authenticated to use 69 | the Like button. The web view does _not_ share cookies with Safari or the 70 | Facebook app, so FacebookLikeView monkeypatches FBConnect to never use those 71 | apps for authentication. 72 | 73 | Unlike a plain web view, FacebookLikeView does not follow redirects. If 74 | redirected to the Facebook login page, it ignores the redirect and calls the 75 | delegate method `facebookLikeViewRequiresLogin:` so that you may present a 76 | dialog instead. 77 | 78 | FacebookLikeView monitors Like/Unlike events using [FB.Event.subscribe]. When 79 | one of those events fires, a bit of JavaScript running inside the web view 80 | encodes the event into a URL request that is intercepted by native code, which 81 | then calls the appropriate delegate method. 82 | 83 | ##Caveats 84 | 85 | FacebookLikeView is not supported by Facebook and is subject to break when 86 | changes are made in the Like button's implementation. 87 | 88 | FacebookLikeView is also not necessarily compatible with future versions of the 89 | Facebook iOS SDK. To ensure compatibility, use the SDK snapshot contained in the 90 | `FBConnect` directory. 91 | 92 | [FB.Event.subscribe]: https://developers.facebook.com/docs/reference/javascript/FB.Event.subscribe 93 | [Like button attributes]: https://developers.facebook.com/docs/reference/plugins/like 94 | --------------------------------------------------------------------------------