PDA

View Full Version : FBConnect Issues With UIWebView




newtoiphonesdk
Aug 23, 2010, 10:42 AM
I have an application that uses a Tab Bar for control. In my thirdviewcontroller I have a webview that I would like to be able to program so that people can connect with facebook, and publish the link the webview is on to their facebook wall. I originally tested just the FBConnect without a webview present, and it worked fine. Afterwards, I added the UIWebView. It will build, but when the UIWebView is present, the FBConnect button will not appear. Here is my .h and .m codes.
.h:
#import <UIKit/UIKit.h>
#import "FBConnect.h"
#import "FBSession.h"


@interface ThirdViewController : UIViewController {
IBOutlet UIWebView *sermons;
IBOutlet UIActivityIndicatorView *activity;
NSTimer *timer;
FBLoginButton *loginButton;
UIAlertView *facebookAlert;
FBSession *usersession;
NSString *username;
BOOL post;

}
@property(nonatomic,retain) FBLoginButton *loginButton;
@property(nonatomic,retain) UIAlertView *facebookAlert;
@property(nonatomic,retain) FBSession *usersession;
@property(nonatomic,retain) NSString *username;
@property(nonatomic,assign) BOOL post;
@property (nonatomic, retain) UIActivityIndicatorView *activity;



- (BOOL)textFieldShouldReturn:(UITextField *)textField;
-(void)getFacebookName;
-(void)postToWall;


@end


.m:
#import "ThirdViewController.h"
#import "BellAvenueAppDelegate.h"

#define _APP_KEY @"REMOVED FOR PRIVACY"
#define _SECRET_KEY @"REMOVED FOR PRIVACY"

@implementation ThirdViewController
@synthesize loginButton;
@synthesize facebookAlert;
@synthesize usersession;
@synthesize username;
@synthesize post;

- (void)awakeFromNib
{
[sermons loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.316apps.com/iphonesermons.html"]]];
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:@selector(tick) userInfo:nil repeats:YES];
NSString *currentURL = sermons.request.URL.absoluteString;
}

-(void)tick {
if(!sermons.loading)
[activity stopAnimating];
else
[activity startAnimating];

}
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/

- (void)viewDidLoad {BellAvenueAppDelegate *appDelegate =
(BellAvenueAppDelegate *) [[UIApplication
sharedApplication]delegate];
if (appDelegate._session == nil){
appDelegate._session = [FBSession
sessionForApplication:_APP_KEY
secret:_SECRET_KEY delegate:self];
}
if(self.loginButton == NULL)
self.loginButton = [[[FBLoginButton alloc] init] autorelease];
loginButton.frame = CGRectMake(124, 91, 72, 37);
[self.view addSubview:loginButton];

[super viewDidLoad];
}

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}


- (void)dealloc {
[username release];
[usersession release];
[loginButton release];
[sermons release];
[super dealloc];
}
- (void)session:(FBSession*)session didLogin:(FBUID)uid {
self.usersession =session;
NSLog(@"User with id %lld logged in.", uid);
[self getFacebookName];
}

- (void)getFacebookName {
NSString* fql = [NSString stringWithFormat:
@"select uid,name from user where uid == %lld",
self.usersession.uid];
NSDictionary* params =
[NSDictionary dictionaryWithObject:fql
forKey:@"query"];
[[FBRequest requestWithDelegate:self]
call:@"facebook.fql.query" params:params];
self.post=YES;
}

- (void)request:(FBRequest*)request didLoad:(id)result {
if ([request.method isEqualToString:@"facebook.fql.query"]) {
NSArray* users = result;
NSDictionary* user = [users objectAtIndex:0];
NSString* name = [user objectForKey:@"name"];
self.username = name;

if (self.post) {
[self postToWall];
self.post = NO;
}
}
}

- (void)postToWall {

FBStreamDialog *dialog = [[[FBStreamDialog alloc] init] autorelease];
dialog.userMessagePrompt = @"Enter Your Message Here:";
dialog.attachment = [NSString currentURL];
[dialog show];

}
@end

UPDATE:
Ok I have it partially solved. Apparently I didn't get very much sleep last night and I have no idea why I did an awakefromnib and viewdidload statements. I moved [sermons loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.316apps.com/iphonesermons.html"]]];
NSString *currentURL = sermons.request.URL.absoluteString;
into the viewdidload, and the FBConnect button will now show. I can login, but when it tries to pull up the publish to wall part, it crashes. Here is what I have for the code for that part.
- (void)postToWall {

FBStreamDialog *dialog = [[[FBStreamDialog alloc] init] autorelease];
dialog.userMessagePrompt = @"Enter Your Message Here:";
dialog.attachment = [NSString currentURL];
[dialog show];

}
What I want it to do is to post a link of the current URL the user is on. I thought that setting up the NSString in the view did load and then setting the dialog.attachment to that NSString would work, but it constantly crashes. Any ideas?



ianray
Aug 23, 2010, 01:21 PM
Does this line even compile?

dialog.attachment = [NSString currentURL];

If so, you have presumably added a category to NSString, so please forgive my question :)

newtoiphonesdk
Aug 23, 2010, 01:33 PM
Everything builds fine, it just crashes when it tries to pull up the dialog box for publishing something to the wall. I do get the warning NSString may not respond to +currenturl

ianray
Aug 23, 2010, 01:44 PM
Everything builds fine, it just crashes when it tries to pull up the dialog box for publishing something to the wall. I do get the warning NSString may not respond to +currenturl

Ah, ok, the thing is -- that warning, in this case, is fatal. NSString does not respond to +currentURL (try right-clicking on currentURL in XCode and selecting "Find Text in Documentation").

More generally, I recommend treating "may not respond to" warnings as errors. The compiler does not have enough information to verify that a certain method exists -- and therefore it is very unlikely that correct behaviour will ensue.

In my projects the Project Build setting is configured with "Treat Warnings as Errors" enabled. A little extreme, perhaps, but it forces one to listen to what the compiler is saying... :D

newtoiphonesdk
Aug 23, 2010, 03:01 PM
I declared it

@interface ThirdViewController : UIViewController {
IBOutlet UIWebView *sermons;
IBOutlet UIActivityIndicatorView *activity;
NSTimer *timer;
FBLoginButton *loginButton;
UIAlertView *facebookAlert;
FBSession *usersession;
NSString *username;
BOOL post;
NSString *currentURL;

}
@property(nonatomic,retain) FBLoginButton *loginButton;
@property(nonatomic,retain) UIAlertView *facebookAlert;
@property(nonatomic,retain) FBSession *usersession;
@property(nonatomic,retain) NSString *username;
@property(nonatomic,assign) BOOL post;
@property (nonatomic, retain) UIActivityIndicatorView *activity;
@property (nonatomic, retain) NSString *currentURL;
I changed it in the post to wall function

- (void)postToWall {

FBStreamDialog *dialog = [[[FBStreamDialog alloc] init] autorelease];
dialog.userMessagePrompt = @"Enter Your Message Here:";
dialog.attachment = currentURL;
[dialog show];

}

The warning went away on the dialog.attachment line when I changed it.

What I have in the ViewDidLoad is this

- (void)viewDidLoad {BellAvenueAppDelegate *appDelegate =
(BellAvenueAppDelegate *) [[UIApplication
sharedApplication]delegate];
if (appDelegate._session == nil){
appDelegate._session = [FBSession
sessionForApplication:_APP_KEY
secret:_SECRET_KEY delegate:self];
}
if(self.loginButton == NULL)
self.loginButton = [[[FBLoginButton alloc] init] autorelease];
loginButton.frame = CGRectMake(124, 91, 72, 37);
[self.view addSubview:loginButton];
[sermons loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.316apps.com/iphonesermons.html"]]];
NSString *currentURL = sermons.request.URL.absoluteString;

[super viewDidLoad];
}
When I build I get the warning on the NSString Line 'unused variable currentURL' and it still crashes.

ianray
Aug 23, 2010, 03:15 PM
When I build I get the warning on the NSString Line 'unused variable currentURL' and it still crashes.

Listen to what the compiler is telling you, and review your understanding about variable declaration versus variable assignment. You are nearly there :)

chown33
Aug 23, 2010, 03:16 PM
Time to start using the debugger.

newtoiphonesdk
Aug 23, 2010, 03:28 PM
I left it as

[sermons loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.316apps.com/iphonesermons.html"]]];
NSString *currentURL = sermons.request.URL.absoluteString;
[super viewDidLoad];

And put a breakpoint in at the dialog.attachment line.
It crashed the app when attempting to redirect to the publish on wall part of the app. Debugger showed the following:
0x94d8aef6 <+0010> jae 0x94d8af06 <__kill+26>
I then ran it with the self.currentURL = sermons.request.URL.absoluteString; in the ViewDidLoad instance and put in a breakpoint. Debugger came up with this.

2010-08-23 15:19:06.506 Bell Avenue[6313:207] -[ThirdViewController setCurrentURL:]: unrecognized selector sent to instance 0x743f170
2010-08-23 15:19:06.510 Bell Avenue[6313:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ThirdViewController setCurrentURL:]: unrecognized selector sent to instance 0x743f170'
*** Call stack at first throw:
(
0 CoreFoundation 0x026f0919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x0283e5de objc_exception_throw + 47
2 CoreFoundation 0x026f242b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x02662116 ___forwarding___ + 966
4 CoreFoundation 0x02661cd2 _CF_forwarding_prep_0 + 50
5 Bell Avenue 0x00002ec3 -[ThirdViewController viewDidLoad] + 747
6 UIKit 0x004cc924 -[UINib instantiateWithOwner:options:] + 1556
7 UIKit 0x004ce4b5 -[NSBundle(UINSBundleAdditions) loadNibNamed:owner:options:] + 168
8 UIKit 0x002dd9bb -[UIApplication _loadMainNibFile] + 172
9 UIKit 0x002de90d -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 198
10 UIKit 0x002e8452 -[UIApplication handleEvent:withNewEvent:] + 1958
11 UIKit 0x002e1074 -[UIApplication sendEvent:] + 71
12 UIKit 0x002e5ac4 _UIApplicationHandleEvent + 7495
13 GraphicsServices 0x02f56afa PurpleEventCallback + 1578
14 CoreFoundation 0x026d1dc4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
15 CoreFoundation 0x02632737 __CFRunLoopDoSource1 + 215
16 CoreFoundation 0x0262f9c3 __CFRunLoopRun + 979
17 CoreFoundation 0x0262f280 CFRunLoopRunSpecific + 208
18 CoreFoundation 0x0262f1a1 CFRunLoopRunInMode + 97
19 UIKit 0x002de226 -[UIApplication _run] + 625
20 UIKit 0x002e9b58 UIApplicationMain + 1160
21 Bell Avenue 0x00002370 main + 102
22 Bell Avenue 0x00002301 start + 53
)
terminate called after throwing an instance of 'NSException'

ianray
Aug 23, 2010, 03:35 PM
CHECK the compiler warnings.

Sorry to shout. This is important. The crash message "unrecognized selector sent to" indicates missing code relating to the property definition for 'currentURL'.

You can do this! Trust yourself, and listen to the compiler :D

newtoiphonesdk
Aug 23, 2010, 03:37 PM
I figured out part of the problem. I forgot to synthesize currentURL. This fixed the viewdidload part of my code. However when I get to post to wall, it is still crashing at the dialog.attachment line of code.

ianray
Aug 23, 2010, 03:44 PM
Great! Now, if you have not already, fix ALL the compiler warnings. Seriously.

BTW is the currentURL in a similar format to that in the example code at http://github.com/facebook/facebook-iphone-sdk/blob/master/samples/Connect/SessionViewController.m? If not, that may be a cause of problems...

newtoiphonesdk
Aug 23, 2010, 03:55 PM
I would assume the currentURL is in standard HTTP format.

I declare the NSString currentURL and synthesize it, the viewdidload is this
- (void)viewDidLoad {BellAvenueAppDelegate *appDelegate =
(BellAvenueAppDelegate *) [[UIApplication
sharedApplication]delegate];
if (appDelegate._session == nil){
appDelegate._session = [FBSession
sessionForApplication:_APP_KEY
secret:_SECRET_KEY delegate:self];
}
if(self.loginButton == NULL)
self.loginButton = [[[FBLoginButton alloc] init] autorelease];
loginButton.frame = CGRectMake(124, 91, 72, 37);
[self.view addSubview:loginButton];
[sermons loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.316apps.com/iphonesermons.html"]]];
self.currentURL = sermons.request.URL.absoluteString;
[super viewDidLoad];
}
the post to wall is this
- (void)postToWall {

FBStreamDialog *dialog = [[[FBStreamDialog alloc] init] autorelease];
dialog.userMessagePrompt = @"Enter Your Message Here:";
dialog.attachment = self.currentURL;
[dialog show];

}


UPDATE:
I cleaned all targets and it will now run without errors, and post to facebook, but it simply will not post the link of the webview's currentURL, it just stays blank.

ianray
Aug 23, 2010, 04:04 PM
I would assume the currentURL is in standard HTTP format.

Did you look at http://github.com/facebook/facebook-iphone-sdk/blob/master/samples/Connect/SessionViewController.m?

In that example, the content stored to "dialog.attachment" appears to be structured -- "attachment" is not actually a URL. As I said, this may be a cause of problems...

newtoiphonesdk
Aug 23, 2010, 04:38 PM
Yea but it seems that you can put stuff there, but it stays the same. I was wanting to use it with a blog page so someone could post their story they are looking at

ianray
Aug 23, 2010, 04:54 PM
Yea but it seems that you can put stuff there, but it stays the same.

Just to be clear...

Is the code is now successfully posting blank information to your facebook time-line?
And is the attachment parameter structured, like in the sample code?

newtoiphonesdk
Aug 23, 2010, 05:12 PM
It posts a blank message to facebook. I don't really have it structured any. All I have on dialog.attachment is currentURL. Do I need to define currenturl in some way?

ianray
Aug 23, 2010, 05:30 PM
It posts a blank message to facebook. I don't really have it structured any. All I have on dialog.attachment is currentURL. Do I need to define currenturl in some way?


Look at http://http://github.com/facebook/facebook-iphone-sdk/blob/master/samples/Connect/SessionViewController.m
Adjust "dialog.attachment" accordingly
???
Profit

newtoiphonesdk
Aug 23, 2010, 05:41 PM
How do I adjust the dialog.attachment to have it post the currenturl? Everything on that post is in "". Doesn't that mean I can change the text and website to something I manually type in, not what is in the currenturl?

dejo
Aug 23, 2010, 06:55 PM
How do I adjust the dialog.attachment to have it post the currenturl? Everything on that post is in "". Doesn't that mean I can change the text and website to something I manually type in, not what is in the currenturl?
You already seem to know how to use NSString's stringWithFormat:. Here's an opportunity to use it again.

newtoiphonesdk
Aug 23, 2010, 07:07 PM
But how would I implement the currenturl into the stringwithformat

dejo
Aug 23, 2010, 07:39 PM
But how would I implement the currenturl into the stringwithformat
Hmm, I guess I was wrong. You don't seem to know how to use it.

I think, based on this and your various queries throughout these forums, that it would behoove you to step away from the real coding and go learn the basics of Objective-C and iPhone development. Find some guided introduction: a book or some tutorials (hint (http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhone101/Articles/00_Introduction.html)). Giving yourself a proper foundation is only going to help you in the long run. Learning the fundamentals should allow you to start to creatively put together your own code based on your own needs.

newtoiphonesdk
Aug 23, 2010, 07:41 PM
Can you not help me in this one instance? I am so close to having this figured out right now

dejo
Aug 23, 2010, 07:54 PM
Can you not help me in this one instance?
Help you how? By giving you the answer? That I won't do.

Have you tried reading the documentation for stringWithFormat: (http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/uid/20000154-stringWithFormat_) ? If or when you have, come back and ask specific questions about things you don't understand and we can move further.

newtoiphonesdk
Aug 23, 2010, 09:05 PM
Ok, here is a different yet similar question. I have the MFMailcomposersheet setup in this as well, attempting to do the same basic thing, email what is in the webview. I set this.
-(void)displayComposerSheet
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;

[picker setSubject:@"Guest Form"];


// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:@"bacoc@amaonline.com"];

[picker setToRecipients:toRecipients];

// Fill out the email body text
NSString *emailBody = self.currentURL;
[picker setMessageBody:emailBody isHTML:YES];

[self presentModalViewController:picker animated:YES];
[picker release];
}
It opens up the composer sheet, but the emailbody stays blank. I tried changing self.currentURL to NSString stringWithFormat:currentURL and it won't compile.

dejo
Aug 23, 2010, 09:58 PM
Ok, here is a different yet similar question.
Not sure why we needed to take this from a different tact but okay...

It opens up the composer sheet, but the emailbody stays blank.
Time for some basic debugging. What is the value of emailBody before you use it for setMessageBody:?

I tried changing self.currentURL to NSString stringWithFormat:currentURL and it won't compile.
Won't compile? Why not? Be specific. Errors/warnings/what?

newtoiphonesdk
Aug 23, 2010, 10:24 PM
I was a little absent minded and didn't have the code typed out the same in my .m as I did in my .h. I fixed this to where it would compile and it works. Here is the code I have in my compose sheet to fill out the email body
// Fill out the email body text
NSString *emailBody = [NSString stringWithFormat:@"<html><head></head><body>%@</body></html>", currentURL];
[picker setMessageBody:emailBody isHTML:YES];

When I do that and click to compose email, the email body simply shows (null).

dejo
Aug 23, 2010, 10:56 PM
Again, basic debugging. What is the value of currentURL before you use it in the stringWithFormat:? (It's probably nil.) Think about why that may be. Trace back to where it is set. Is it being assigned as expected? If not, why not? Etc.

Also, since it's a property, you should reference it via the getter you synthesized, i.e. self.currentURL.

newtoiphonesdk
Aug 23, 2010, 11:32 PM
Where in the debugger do I get the value of currentURL?
UPDATE:
Crashing for the night. Been banging my head against the wall trying to figure out why currentURL is coming back as nil. .h has it declared and property. .m has it synthesized. ViewDidLoad of view controller has the request for absolutestring. The webview will load to the predetermined page, but currentURL always shows as nil, and I can't figure out why.

Ran an NSLog. It only got pulled once showing:
Attaching to process 9544.
2010-08-24 10:14:25.964 Bell Avenue[9544:207] sermons called, currentURL set to (null)
[Switching to process 9544]

ianray
Aug 24, 2010, 01:10 PM
The webview will load to the predetermined page, but currentURL always shows as nil, and I can't figure out why.

You've made good progress! -- You now know the failure location.

[sermons loadRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:@"http://www.316apps.com/iphonesermons.html"]]];

// sermons.request.URL.absoluteString returns nil
self.currentURL = sermons.request.URL.absoluteString;

Now... to figure out why. It may be:


The "sermons" object is not ready
Bug in iOS
Enemy action


Is this an academic exercise? I only ask because a literal URL was included in the loadRequest...

newtoiphonesdk
Aug 24, 2010, 01:35 PM
It's for our church. I'm the most techie person we have

ianray
Aug 24, 2010, 01:38 PM
I'll rephrase the question. Given (the text highlighted in bold),

[sermons loadRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:@"http://www.316apps.com/iphonesermons.html"]]];


then, why do you need (the text highlighted in bold) ?

self.currentURL = sermons.request.URL.absoluteString;

newtoiphonesdk
Aug 24, 2010, 03:15 PM
I'll rephrase the question. Given (the text highlighted in bold),

[sermons loadRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:@"http://www.316apps.com/iphonesermons.html"]]];


then, why do you need (the text highlighted in bold) ?

self.currentURL = sermons.request.URL.absoluteString;
I was doing some testing on this and had changed the website from what it actually will be. The website it opens to originally will be http://bacocnews.wordpress.com. The reason I was needing to get currentURL is the idea that someone could read an article in the blog, and then click the email button and have it email the site of the article they had clicked on, instead of the original loading page.

ianray
Aug 24, 2010, 04:50 PM
The reason I was needing to get currentURL is the idea that someone could read an article in the blog, and then click the email button and have it email the site of the article they had clicked on, instead of the original loading page.

Sounds like you need to get the URL on demand, as opposed to attempting (and failing) to get it before the UIWebView is ready... :)

newtoiphonesdk
Aug 24, 2010, 04:58 PM
You mean maybe putting it in a webviewdidfinishload void instead of void viewdidload?

ianray
Aug 24, 2010, 05:11 PM
You mean maybe putting it in a webviewdidfinishload void instead of void viewdidload?

Using webViewDidFinishLoad sounds very promising ;)

On the other hand you could simply get the current URL when the user clicks the email button.

newtoiphonesdk
Aug 24, 2010, 05:28 PM
The email button is connected to an IBaction to view the mail composer sheet. Is it still possible to put it in there with that?

newtoiphonesdk
Aug 24, 2010, 08:26 PM
I finally got it to work with the email part! When I got back to my computer I put the self.currentURL line in with the IBAction to pull up the mail composer, and it worked like a charm. Thanks for all the help! If anyone has similar issues and would like to see a snippet of the code used for this just PM me.