Error de Android API 3.0 de Facebook: no se puede llamar a LoginActivity con un paquete de llamada nulo

Intento integrar una aplicación de Android con la nueva API 3.0 de Facebook, pero obtengo esta excepción:

java.lang.RuntimeException: no se puede reanudar la actividad {dk.imu.konnekt / com.facebook.LoginActivity}: com.facebook.FacebookException: no se puede llamar a LoginActivity con un paquete de llamadas nulo. Esto puede ocurrir si el launchMode de la persona que llama es singleInstance.

He buscado este error, pero nadie más parece haber tenido ningún problema con él. Supongo que es porque estoy usando TabHost y TabsGroupActivities para cada pestaña. Pero no tengo idea de cómo resolverlo.

He agregado el código relevante aquí:

public class MainTabActivity extends TabActivity { public void onCreate(Bundle savedInstanteState){ super.onCreate(savedInstanteState); setContentView(R.layout.tab_layout); TabHost tabHost = getTabHost(); View shareTab = getLayoutInflater().inflate(R.layout.share_tab, null); tabHost.addTab(tabHost.newTabSpec("Share").setIndicator(shareTab) .setContent(new Intent(MainTabActivity.this, ShareGroupActivity.class))); ... } } 

 public class ShareGroupActivity extends TabsGroupActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); startChildActivity("ShareActivity", new Intent(this, ShareActivity.class)); } } 

 public class ShareActivity extends BaseActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.share); testFacebookConnection(); } public void testFacebookConnection(){ Session session = new Session(this); Session.setActiveSession(session); SessionState state = session.getState(); Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS); Session.StatusCallback statusCallback = new Session.StatusCallback() { @Override public void call(Session session, SessionState state, Exception exception) { Toast.makeText(ShareActivity.this, "Facebook session status changed", Toast.LENGTH_SHORT).show(); } }; if (!session.isOpened() && !session.isClosed() && session.getState() != SessionState.OPENING) { OpenRequest open = new OpenRequest(this).setCallback(statusCallback); List permission = new ArrayList(); permission.add("publish_actions"); open.setPermissions(permission); session.openForPublish(open); } else { Session.openActiveSession(this, true, statusCallback); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data); } } 

¿Alguna pista sobre cómo resolverlo?

Actualizar 1 rastro de stack:

EXCEPCIÓN FATAL: main java.lang.RuntimeException: no se puede reanudar la actividad {dk.imu.konnekt / com.facebook.LoginActivity}: com.facebook.FacebookException: no se puede llamar a LoginActivity con un paquete de llamadas nulo. Esto puede ocurrir si el launchMode de la persona que llama es singleInstance. en android.app.ActivityThread.performResumeActivity (ActivityThread.java:2812) en android.app.ActivityThread.handleResumeActivity (ActivityThread.java:2851) en android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2234) en android.app. ActivityThread.access $ 600 (ActivityThread.java:139) en android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1261) en android.os.Handler.dispatchMessage (Handler.java:99) android.os.Looper.loop (Looper.java:154) en android.app.ActivityThread.main (ActivityThread.java:4945) en java.lang.reflect.Method.invokeNative (método nativo) en java.lang.reflect.Method.invoke (Method.java : 511) en com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:784) en com.android.internal.os.ZygoteInit.main (ZygoteInit.java:551) en dalvik.system.NativeStart. main (Método nativo) Causado por: com.facebook.FacebookException: No se puede llamar a LoginActivity con un paquete de llamada nulo. Esto puede ocurrir si el launchMode de la persona que llama es singleInstance. en com.facebook.LoginActivity.onResume (LoginActivity.java:110) en android.app.Instrumentation.callActivityOnResume (Instrumentation.java:1236) en android.app.Activity.performResume (Activity.java:4613) en android.app. ActivityThread.performResumeActivity (ActivityThread.java:2796) … 12 más

Actualización 2: revisé el código y encontré la implementación de startChildActivity:

 public void startChildActivity(String Id, Intent intent) { Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); if (window != null) { mIdList.add(Id); setContentView(window.getDecorView()); } } 

Utiliza la bandera FLAG_ACTIVITY_CLEAR_TOP. Intenté eliminarlo, pero no cambié el resultado.

Actualización 3:

https://github.com/facebook/facebook-android-sdk/blob/master/facebook/src/com/facebook/LoginActivity.java

El código de Facebook usa

 callingPackage = getCallingPackage(); 

y

 if (callingPackage == null) { throw new FacebookException(NULL_CALLING_PKG_ERROR_MSG); } 

http://developer.android.com/reference/android/app/Activity.html#getCallingPackage ()

Este método tiene una nota:

Si la actividad de llamada no espera un resultado (es decir, no usó el formulario startActivityForResult (Intent, int) que incluye un código de solicitud), el paquete de llamada será nulo.

En el método startChildActivity utilizo getLocalActivityManager (). StartActivity, en TabsGroupActivity que amplía ActivityGroup, para manejar actividades de tabs. http://developer.android.com/reference/android/app/LocalActivityManager.html#startActivity(java.lang.String, android.content.Intent)

Este método no dice lo que dicen las notas. No espera un resultado y no utiliza el método startActivityForResult. El método también asegura algo similar al modo de inicio de instancia única. ¿Cómo debo cambiar la implementación de este método para que pueda funcionar con Facebook?

Logré encontrar mi problema Aunque no estaba estableciendo

android: launchMode = “singleTask”

mi LoginActivity tenía

android: noHistory = “true”

que resulta en esa excepción. No puse ninguna historia verdadera porque no quería que el usuario pudiera presionar el botón Atrás en la primera actividad después de iniciar sesión y volver a la pantalla de inicio de sesión. Ahora necesito encontrar otra solución.

Después de muchas búsquedas, me di cuenta de que no parece haber una manera de iniciar Activity ForResult con LocalActivityManager en las tabs.

Así que terminé aceptando que necesitará una actividad que llene toda la pantalla. La actividad solo se muestra un segundo más o menos con una buena conexión de red. Lo he hecho con una opción de republicación de errores también.

Comience la actividad de publicación:

 Intent intent = new Intent(this, FacebookShareActivity.class); intent.putExtra(Constants.FACEBOOK_MESSAGE, shareMessage.getMessage()); startActivityForResult(intent, 1); 

Código de actividad de Facebook compartido: publicación en la pared de los usuarios:

 public class FacebookShareActivity extends Activity { String message; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.facebook_publishing); message = getIntent().getExtras().getString(Constants.FACEBOOK_MESSAGE); createFacebookConnection(); } public void republishButton_Click(View view){ setVisibilityForRepublishButton(false); createFacebookConnection(); } public void createFacebookConnection() { Session session = new Session(this); Session.setActiveSession(session); Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS); Session.StatusCallback statusCallback = new Session.StatusCallback() { @Override public void call(Session session, SessionState state, Exception exception) { String message = "Facebook session status changed - " + session.getState() + " - Exception: " + exception; //Toast.makeText(FacebookShareActivity.this, message, Toast.LENGTH_SHORT).show(); Log.w("Facebook test", message); if (session.isOpened() || session.getPermissions().contains("publish_actions")) { publishToWall(); } else if (session.isOpened()) { OpenRequest open = new OpenRequest(FacebookShareActivity.this).setCallback(this); List permission = new ArrayList(); permission.add("publish_actions"); open.setPermissions(permission); Log.w("Facebook test", "Open for publish"); session.openForPublish(open); } } }; if (!session.isOpened() && !session.isClosed() && session.getState() != SessionState.OPENING) { session.openForRead(new Session.OpenRequest(this).setCallback(statusCallback)); } else { Log.w("Facebook test", "Open active session"); Session.openActiveSession(this, true, statusCallback); } } private void setVisibilityForRepublishButton(Boolean visible) { ((Button) findViewById(R.id.republishButton)).setVisibility(visible ? View.VISIBLE : View.GONE); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data); //Toast.makeText(FacebookShareActivity.this, "onActivityResult", Toast.LENGTH_SHORT).show(); } void publishToWall() { Session session = Session.getActiveSession(); Bundle postParams = new Bundle(); postParams.putString("message", message); final Context context = this; Request.Callback callback = new Request.Callback() { public void onCompleted(Response response) { FacebookRequestError error = response.getError(); if (error != null) { setVisibilityForRepublishButton(true); Toast.makeText(context, error.getErrorMessage(), Toast.LENGTH_SHORT).show(); } else { JSONObject graphResponse = response.getGraphObject().getInnerJSONObject(); String postId = null; try { postId = graphResponse.getString("id"); } catch (JSONException e) { setVisibilityForRepublishButton(true); Log.i("Facebook error", "JSON error " + e.getMessage()); } //Toast.makeText(context, postId, Toast.LENGTH_LONG).show(); finish(); } } }; Request request = new Request(Session.getActiveSession(), "me/feed", postParams, HttpMethod.POST, callback); RequestAsyncTask task = new RequestAsyncTask(request); task.execute(); } } 

Tengo el mismo problema: intentar iniciar sesión en Facebook, con el diálogo proporcionado dentro del SDK, pero desde una actividad que estaba dentro de un grupo de tabulación; como ShareActivity arriba.

Lo que he hecho se llama básicamente startActivityForResult en la actividad principal de ShareActivity (es decir, ShareGroupActivity), en lugar de llamarlo en ShareActivity.

Entonces 1, agregue esto en ShareGroupActivity:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { System.out.println("facebook status called"); super.onActivityResult(requestCode, resultCode, data); Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data); } 

2 necesita modificar la clase Session, dentro del proyecto FacebookSDK, bajo src com.facebook

2.1 agregar un miembro booleano

 public boolean insideTabGroup; 

2.2 modifique StartActivityDelegate, que la sesión utiliza para abrir el inicio de sesión; agregue el booleano como parámetro

 interface StartActivityDelegate { public void startActivityForResult(Intent intent, int requestCode, boolean insideTabGroup); public Activity getActivityContext(); } 

2.3 dentro de la clase interna AuthorizationRequest, modifique la implementación de este delegado:

  AuthorizationRequest(final Activity activity) { startActivityDelegate = new StartActivityDelegate() { @Override public void startActivityForResult(Intent intent, int requestCode, boolean insideTabGroup) { if(insideTabGroup) { ActivityGroup parentActivity = (ActivityGroup) activity.getParent(); parentActivity.startActivityForResult(intent,requestCode); } else { activity.startActivityForResult(intent, requestCode); } } @Override public Activity getActivityContext() { return activity; } }; } 

2.4 Además, modifique los otros constructores de AuthorizationRequest, simplemente agregando el parámetro booleano. Como no uso el inicio de sesión de Facebook en otro lugar que no sea una actividad, está bien.

2.5 Modifique el método tryLoginActivity de la clase Session, para usar el miembro booleano como parámetro:

 private boolean tryLoginActivity(AuthorizationRequest request) { Intent intent = getLoginActivityIntent(request); if (!resolveIntent(intent)) { return false; } try { request.getStartActivityDelegate().startActivityForResult(intent, request.getRequestCode(),this.insideTabGroup); } catch (ActivityNotFoundException e) { return false; } return true; } 

3 Establezca el miembro booleano en la sesión:

 Session session = Session.getActiveSession(); session.insideTabGroup = true; 

Eso debería hacer el truco.

Cdt

Tuve el mismo error con la integración de SDK de Facebook de Parse.com y me quedé sin la llamada a ParseFacebookUtils.finishAuthentication que se menciona en los documentos .

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); ParseFacebookUtils.finishAuthentication(requestCode, resultCode, data); }