Android & Facebook SDK:无需登录按钮获取用户数据
Android & Facebook SDK: Obtain user data without Login Button
我在尝试将 Facebook 与应用程序集成时失去了理智。首先,Fb 的 SDK 很糟糕,自从我包含它后,它让一切都崩溃了。无论如何,我正在尝试从 Facebook 获取用户数据,只是 his/her 姓名、用户 ID 和电子邮件;但是,我不能使用登录按钮,因为它不支持嵌套片段,并且它使用 UiLifecycleHelper 保持会话打开并继续执行我只想调用一次的回调。
我不需要保持会话打开;我会在用户第一次使用该应用程序时偶尔打开会话,如果 he/she 想要发布一些东西(非常罕见)。
到目前为止,我已经尝试使用登录按钮,执行一个简单的请求并将两者结合起来。不过,SDK整体上好像和Nested Fragment玩的不太好。
这是我最后一次尝试完成这项工作(这两个方法在 Fragment 中。按下按钮后,将执行 performFacebookLogin):
public void performFacebookLogin() {
Session.openActiveSession(getActivity(), true, Arrays.asList("email"), new Session.StatusCallback() {
@Override
public void call(Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
Log.d("FACEBOOK", "Session has been opened");
Request.newMeRequest(session, new Request.GraphUserCallback() {
@Override
public void onCompleted(GraphUser user, Response response) {
Log.d("FACEBOOK", "onCompleted");
if (user != null) {
Log.d("DBG", buildUserInfoDisplay(user));
}
}
}).executeAsync();
}else{
//TODO: ERROR
Log.e("FACEBOOK", "Session could not be opened");
}
}
});
}
private String buildUserInfoDisplay(GraphUser user) {
StringBuilder userInfo = new StringBuilder("");
userInfo.append(String.format("Name: %s\n\n",
user.getName()));
userInfo.append(String.format("Email: %s\n\n",
user.getProperty("email")));
userInfo.append(String.format("ID: %s\n\n",
user.getId()));
return userInfo.toString();
}
那么,会发生什么?显示对话框提示以便使用您的 Facebook 帐户登录。但是,一旦您按下“登录”并且对话框消失,就什么也没有发生。 LogCat 中没有显示任何内容。我认为是 onActivityResult 方法的问题,因为永远不会执行回调。我尝试重新添加 UiLifecycleHelper,但它最终对回调进行了不需要的调用(我只想调用此方法一次)。
你是对的,你需要将结果传递到活动会话才能激活你的回调。在您的活动 onActivityForResult 方法中,调用活动会话 onActivityResult,类似于:https://github.com/facebook/facebook-android-sdk/blob/master/facebook/src/com/facebook/UiLifecycleHelper.java#L156-159
Session session = Session.getActiveSession();
if (session != null) {
session.onActivityResult(activity, requestCode, resultCode, data);
}
这将使您的回调正常工作。
因此,我设法实现了解决我的问题的模块化方法:我创建了一个 activity,它封装了与 Facebook SDK 的连接,并通过 onActivityResult return 进行连接。不幸的是,我还没有找到将结果直接 return 到嵌套片段的方法。
另外,您可以使 activity 透明以避免黑屏,并在需要时添加更多权限。此外,如果要保持 Session 处于活动状态,则可以删除 onStop 方法。
这是代码:
public class FacebookAccessActivity extends ActionBarActivity {
public static final String PARAM_PROFILE = "public_profile";
public static final String PARAM_EMAIL = "email";
public static final String PARAM_FIRSTNAME = "fname";
public static final String PARAM_LASTNAME = "lname";
public static final String PARAM_GENDER = "gender";
public static final String PARAM_BDAY = "user_birthday";
public static final String PARAM_ID = "id";
private static Session session = null;
private List<String> permissions = Arrays.asList(PARAM_EMAIL, PARAM_PROFILE, PARAM_BDAY);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.view_empty);
session = Session.getActiveSession();
if (session != null)
session.closeAndClearTokenInformation();
Session.openActiveSession(this, true, permissions, new Session.StatusCallback() {
@Override
public void call(Session session, SessionState state, Exception exception) {
if (exception != null || state == SessionState.CLOSED_LOGIN_FAILED) {
exception.printStackTrace();
setResult(RESULT_CANCELED);
finish();
} else if (session.isOpened()) {
Request.newMeRequest(session, new Request.GraphUserCallback() {
@Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
Intent i = new Intent();
i.putExtra(PARAM_FIRSTNAME, user.getFirstName());
i.putExtra(PARAM_LASTNAME, user.getLastName());
i.putExtra(PARAM_ID, user.getId());
i.putExtra(PARAM_GENDER, (String) user.getProperty(PARAM_GENDER));
i.putExtra(PARAM_BDAY, user.getBirthday());
for (String s : permissions)
i.putExtra(s, (String) user.getProperty(s));
setResult(RESULT_OK, i);
finish();
}
}
}).executeAsync();
}
}
});
}
@Override
protected void onStop() {
super.onStop();
if (session != null)
session.closeAndClearTokenInformation();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_CANCELED ||
!Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data)) {
setResult(RESULT_CANCELED);
finish();
}
}
我在尝试将 Facebook 与应用程序集成时失去了理智。首先,Fb 的 SDK 很糟糕,自从我包含它后,它让一切都崩溃了。无论如何,我正在尝试从 Facebook 获取用户数据,只是 his/her 姓名、用户 ID 和电子邮件;但是,我不能使用登录按钮,因为它不支持嵌套片段,并且它使用 UiLifecycleHelper 保持会话打开并继续执行我只想调用一次的回调。
我不需要保持会话打开;我会在用户第一次使用该应用程序时偶尔打开会话,如果 he/she 想要发布一些东西(非常罕见)。
到目前为止,我已经尝试使用登录按钮,执行一个简单的请求并将两者结合起来。不过,SDK整体上好像和Nested Fragment玩的不太好。
这是我最后一次尝试完成这项工作(这两个方法在 Fragment 中。按下按钮后,将执行 performFacebookLogin):
public void performFacebookLogin() {
Session.openActiveSession(getActivity(), true, Arrays.asList("email"), new Session.StatusCallback() {
@Override
public void call(Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
Log.d("FACEBOOK", "Session has been opened");
Request.newMeRequest(session, new Request.GraphUserCallback() {
@Override
public void onCompleted(GraphUser user, Response response) {
Log.d("FACEBOOK", "onCompleted");
if (user != null) {
Log.d("DBG", buildUserInfoDisplay(user));
}
}
}).executeAsync();
}else{
//TODO: ERROR
Log.e("FACEBOOK", "Session could not be opened");
}
}
});
}
private String buildUserInfoDisplay(GraphUser user) {
StringBuilder userInfo = new StringBuilder("");
userInfo.append(String.format("Name: %s\n\n",
user.getName()));
userInfo.append(String.format("Email: %s\n\n",
user.getProperty("email")));
userInfo.append(String.format("ID: %s\n\n",
user.getId()));
return userInfo.toString();
}
那么,会发生什么?显示对话框提示以便使用您的 Facebook 帐户登录。但是,一旦您按下“登录”并且对话框消失,就什么也没有发生。 LogCat 中没有显示任何内容。我认为是 onActivityResult 方法的问题,因为永远不会执行回调。我尝试重新添加 UiLifecycleHelper,但它最终对回调进行了不需要的调用(我只想调用此方法一次)。
你是对的,你需要将结果传递到活动会话才能激活你的回调。在您的活动 onActivityForResult 方法中,调用活动会话 onActivityResult,类似于:https://github.com/facebook/facebook-android-sdk/blob/master/facebook/src/com/facebook/UiLifecycleHelper.java#L156-159
Session session = Session.getActiveSession();
if (session != null) {
session.onActivityResult(activity, requestCode, resultCode, data);
}
这将使您的回调正常工作。
因此,我设法实现了解决我的问题的模块化方法:我创建了一个 activity,它封装了与 Facebook SDK 的连接,并通过 onActivityResult return 进行连接。不幸的是,我还没有找到将结果直接 return 到嵌套片段的方法。 另外,您可以使 activity 透明以避免黑屏,并在需要时添加更多权限。此外,如果要保持 Session 处于活动状态,则可以删除 onStop 方法。 这是代码:
public class FacebookAccessActivity extends ActionBarActivity {
public static final String PARAM_PROFILE = "public_profile";
public static final String PARAM_EMAIL = "email";
public static final String PARAM_FIRSTNAME = "fname";
public static final String PARAM_LASTNAME = "lname";
public static final String PARAM_GENDER = "gender";
public static final String PARAM_BDAY = "user_birthday";
public static final String PARAM_ID = "id";
private static Session session = null;
private List<String> permissions = Arrays.asList(PARAM_EMAIL, PARAM_PROFILE, PARAM_BDAY);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.view_empty);
session = Session.getActiveSession();
if (session != null)
session.closeAndClearTokenInformation();
Session.openActiveSession(this, true, permissions, new Session.StatusCallback() {
@Override
public void call(Session session, SessionState state, Exception exception) {
if (exception != null || state == SessionState.CLOSED_LOGIN_FAILED) {
exception.printStackTrace();
setResult(RESULT_CANCELED);
finish();
} else if (session.isOpened()) {
Request.newMeRequest(session, new Request.GraphUserCallback() {
@Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
Intent i = new Intent();
i.putExtra(PARAM_FIRSTNAME, user.getFirstName());
i.putExtra(PARAM_LASTNAME, user.getLastName());
i.putExtra(PARAM_ID, user.getId());
i.putExtra(PARAM_GENDER, (String) user.getProperty(PARAM_GENDER));
i.putExtra(PARAM_BDAY, user.getBirthday());
for (String s : permissions)
i.putExtra(s, (String) user.getProperty(s));
setResult(RESULT_OK, i);
finish();
}
}
}).executeAsync();
}
}
});
}
@Override
protected void onStop() {
super.onStop();
if (session != null)
session.closeAndClearTokenInformation();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_CANCELED ||
!Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data)) {
setResult(RESULT_CANCELED);
finish();
}
}