web-dev-qa-db-fra.com

Android Facebook api 3.0 erreur: Impossible d'appeler LoginActivity avec un package d'appel null

J'essaie d'intégrer une application Android à la nouvelle api de Facebook 3.0, mais j'obtiens cette exception:

Java.lang.RuntimeException: impossible de reprendre l'activité {dk.imu.konnekt/com.facebook.LoginActivity}: com.facebook.FacebookException: impossible d'appeler LoginActivity avec un package d'appel null. Cela peut se produire si le launchMode de l'appelant est singleInstance.

J'ai recherché cette erreur mais personne ne semble avoir eu de troble avec elle. J'imagine que c'est parce que j'utilise TabHost et TabsGroupActivities pour chaque onglet. Mais je n'ai aucune idée sur la façon de le résoudre.

J'ai ajouté le code correspondant ici:

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<String> permission = new ArrayList<String>();
            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);
    }
}

Un indice sur la façon de le résoudre?

Mise à jour de la trace de pile:

EXCEPTION FATALE: exception Java.lang.RuntimeException principale: impossible de reprendre l'activité {dk.imu.konnekt/com.facebook.LoginActivity}: com.facebook.FacebookException: impossible d'appeler LoginActivity avec un package d'appel nul. Cela peut se produire si le launchMode de l'appelant est singleInstance. sur Android.app.ActivityThread.performResumeActivity (ActivityThread.Java:2812) sur Android.app.ActivityThread.handleResumeActivity (ActivityThread.Java:2851) sur Android.app.ActivityThread.handleLaunchActivity (ActivityThread.Java:2234) sur Android. ActivityThread.access 600 $ (ActivityThread.Java:139) sur Android.app.ActivityThread $ H.handleMessage (ActivityThread.Java:1261) sur Android.os.Handler.dispatchMessage (Handler.Java:99) Android.os.Looper.loop (Looper.Java:154) sur Android.app.ActivityThread.main (ActivityThread.Java:4945) sur Java.lang.reflect.Method.invokeNative (Méthode native) sur Java.lang.reflect.Method.invoke (Method.Java : 511) sur com.Android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.Java:784) sur com.Android.internal.os.ZygoteInit.main (ZygoteInit.Java:551) sur dalvik.system.NativeStart. main (méthode native) Causée par: com.facebook.FacebookException: impossible d'appeler LoginActivity avec un package d'appel null. Cela peut se produire si le launchMode de l'appelant est singleInstance. sur com.facebook.LoginActivity.onResume (LoginActivity.Java:110) sur Android.app.Instrumentation.callActivityOnResume (Instrumentation.Java:1236) sur Android.app.Activity.performResume (Activity.Java:4613) sur Android.app. ActivityThread.performResumeActivity (ActivityThread.Java:2796) ... 12 plus

Mise à jour 2: J'ai parcouru le code et trouvé l'implémentation 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()); 
   }    
}

Il utilise le drapeau FLAG_ACTIVITY_CLEAR_TOP. J'ai essayé de l'enlever, mais aucun changement dans le résultat.

Mise à jour 3:

https://github.com/facebook/facebook-Android-sdk/blob/master/facebook/src/com/facebook/LoginActivity.Java

Le code Facebook utilise

callingPackage = getCallingPackage();

et

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

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

Cette méthode a une note:

Si l'activité appelante n'attend pas de résultat (c'est-à-dire qu'elle n'a pas utilisé le formulaire startActivityForResult (Intent, int) qui inclut un code de requête), le package appelant sera alors nul.

Dans la méthode startChildActivity, j'utilise getLocalActivityManager (). StartActivity, dans TabsGroupActivity qui étend ActivityGroup, pour gérer les activités des onglets. http://developer.Android.com/reference/Android/app/LocalActivityManager.html#startActivity(Java.lang.String, Android.content.Intent)

Cette méthode ne correspond pas à ce que disent les notes. Il n'attend pas de résultat et n'utilise pas la méthode startActivityForResult. La méthode garantit également quelque chose de similaire au mode de lancement à une seule instance. Comment dois-je changer cette implémentation de méthode pour qu'elle puisse fonctionner avec facebook?

20
Morten Holmgaard

Après de nombreuses recherches, j'ai compris qu'il ne semblait pas y avoir de moyen de démarrerActivityForResult avec LocalActivityManager utilisé dans les onglets.

J'ai donc fini par accepter qu'il faudrait une activité remplissant tout l'écran. L'activité ne s'affiche qu'une seconde ou deux avec une bonne connexion réseau - je l'ai également créée avec une option de republication des erreurs.

Commencer l'activité de publication:

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

Code d'activité de partage Facebook - publication sur le mur des utilisateurs:

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<String> permission = new ArrayList<String>();
                    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();
    }
}
5
Morten Holmgaard

J'ai réussi à trouver mon problème. Bien que je ne mette pas

Android: launchMode = "singleTask"

mon LoginActivity avait

Android: noHistory = "true"

ce qui entraîne cette exception. Je mets noHistory à la place car je ne voulais pas que l'utilisateur puisse appuyer sur le bouton de retour lors de la première activité après la connexion et revenir à l'écran de connexion. Maintenant, je dois trouver une autre solution.

7
Raphael Oliveira

J'ai le même problème: essayer de se connecter à Facebook, avec la boîte de dialogue fournie à l'intérieur du SDK, mais à partir d'une activité qui était elle-même dans un groupe de tabulation; comme ShareActivity ci-dessus.

Ce que j'ai fait s'appelle fondamentalement startActivityForResult sur l'activité parente de ShareActivity (c'est-à-dire ShareGroupActivity), au lieu de l'appeler sur ShareActivity.

Alors 1, ajoutez ceci dans 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 vous devez modifier la classe Session dans le projet FacebookSDK, sous src com.facebook

2.1 ajouter un membre booléen

public boolean insideTabGroup;

2.2 modifier StartActivityDelegate, utilisé par la session pour ouvrir une connexion; ajoute le booléen comme paramètre

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

    public Activity getActivityContext();
}

2.3 dans la classe interne AuthorizationRequest, modifiez l'implémentation de ce délégué:

    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 Modifiez également les autres constructeurs de AuthorizationRequest en ajoutant simplement le paramètre boolean. Comme je ne me connecte pas à Facebook depuis ailleurs que pour une activité, ça va.

2.5 Modifiez la méthode tryLoginActivity de la classe Session pour utiliser le membre booléen en tant que paramètre:

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 Définissez le membre booléen dans la session:

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

Cela devrait faire l'affaire.

Cdt

2
Sandro

J'ai eu la même erreur avec l'intégration du SDK Facebook de Parse.com et il me manquait l'appel à ParseFacebookUtils.finishAuthentication qui est noté dans/ docs .

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