androidandroid-volleytwitter-fabricandroid-twitter

Login to twitter always goes to callback failure method


No errors showing but when the button is clicked, it always goes to callback the failure method.Internet is active and the keys are valid. I used debugger to see the following result:-

E/Twitter: Invalid json: <?xml version="1.0" encoding="UTF-8"?>
       <hash>
         <error>Desktop applications only support the oauth_callback value 'oob'</error>
         <request>/oauth/request_token</request>
       </hash>

       com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
           at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
           at com.twitter.sdk.android.core.models.SafeListAdapter$1.read(SafeListAdapter.java:45)
           at com.twitter.sdk.android.core.models.SafeMapAdapter$1.read(SafeMapAdapter.java:45)
           at com.google.gson.Gson.fromJson(Gson.java:879)
           at com.google.gson.Gson.fromJson(Gson.java:844)
           at com.google.gson.Gson.fromJson(Gson.java:793)
           at com.google.gson.Gson.fromJson(Gson.java:765)
           at com.twitter.sdk.android.core.TwitterApiException.parseApiError(TwitterApiException.java:111)
           at com.twitter.sdk.android.core.TwitterApiException.readApiError(TwitterApiException.java:96)
           at com.twitter.sdk.android.core.TwitterApiException.<init>(TwitterApiException.java:44)
           at com.twitter.sdk.android.core.Callback.onResponse(Callback.java:42)
           at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
           at android.os.Handler.handleCallback(Handler.java:739)
           at android.os.Handler.dispatchMessage(Handler.java:95)
           at android.os.Looper.loop(Looper.java:148)
           at android.app.ActivityThread.main(ActivityThread.java:5417)
           at java.lang.reflect.Method.invoke(Native Method)
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
        Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
           at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:387)
           at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:209)
           at com.twitter.sdk.android.core.models.SafeListAdapter$1.read(SafeListAdapter.java:45) 
           at com.twitter.sdk.android.core.models.SafeMapAdapter$1.read(SafeMapAdapter.java:45) 
           at com.google.gson.Gson.fromJson(Gson.java:879) 
           at com.google.gson.Gson.fromJson(Gson.java:844) 
           at com.google.gson.Gson.fromJson(Gson.java:793) 
           at com.google.gson.Gson.fromJson(Gson.java:765) 
           at com.twitter.sdk.android.core.TwitterApiException.parseApiError(TwitterApiException.java:111) 
           at com.twitter.sdk.android.core.TwitterApiException.readApiError(TwitterApiException.java:96) 
           at com.twitter.sdk.android.core.TwitterApiException.<init>(TwitterApiException.java:44) 
           at com.twitter.sdk.android.core.Callback.onResponse(Callback.java:42) 
           at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68) 
           at android.os.Handler.handleCallback(Handler.java:739) 
           at android.os.Handler.dispatchMessage(Handler.java:95) 
           at android.os.Looper.loop(Looper.java:148) 
           at android.app.ActivityThread.main(ActivityThread.java:5417) 
           at java.lang.reflect.Method.invoke(Native Method) 
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
E/Twitter: Failed to get request token
       com.twitter.sdk.android.core.TwitterApiException: HTTP request failed, Status: 401
           at com.twitter.sdk.android.core.Callback.onResponse(Callback.java:42)
           at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
           at android.os.Handler.handleCallback(Handler.java:739)
           at android.os.Handler.dispatchMessage(Handler.java:95)
           at android.os.Looper.loop(Looper.java:148)
           at android.app.ActivityThread.main(ActivityThread.java:5417)
           at java.lang.reflect.Method.invoke(Native Method)
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
E/Twitter: Authorization completed with an error
       com.twitter.sdk.android.core.TwitterAuthException: Failed to get request token
           at com.twitter.sdk.android.core.identity.OAuthController$1.failure(OAuthController.java:95)
           at com.twitter.sdk.android.core.internal.oauth.OAuth1aService$1.failure(OAuth1aService.java:194)
           at com.twitter.sdk.android.core.Callback.onResponse(Callback.java:42)
           at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
           at android.os.Handler.handleCallback(Handler.java:739)
           at android.os.Handler.dispatchMessage(Handler.java:95)
           at android.os.Looper.loop(Looper.java:148)
           at android.app.ActivityThread.main(ActivityThread.java:5417)
           at java.lang.reflect.Method.invoke(Native Method)
           at   com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Main Activity

package com.integrationtutorial;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.twitter.sdk.android.Twitter;
import com.twitter.sdk.android.core.Callback;
import com.twitter.sdk.android.core.Result;
import com.twitter.sdk.android.core.TwitterAuthConfig;
import com.twitter.sdk.android.core.TwitterAuthToken;
import com.twitter.sdk.android.core.TwitterException;
import com.twitter.sdk.android.core.TwitterSession;
import com.twitter.sdk.android.core.identity.TwitterLoginButton;
import com.twitter.sdk.android.core.models.User;

import io.fabric.sdk.android.Fabric;
import retrofit2.Call;

public class MainActivity extends AppCompatActivity
{

//This is your KEY and SECRET
//And it would be added automatically while the configuration
private static final String TWITTER_KEY = "KEY_HERE";
private static final String TWITTER_SECRET = "KEY_HERE";

//Tags to send the username and image url to next activity using intent
public static final String KEY_USERNAME = "username";
public static final String KEY_PROFILE_IMAGE_URL = "image_url";

//Twitter Login Button
TwitterLoginButton twitterLoginButton;


@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);

    //Initializing TwitterAuthConfig, these two line will also added automatically while configuration we did
    TwitterAuthConfig authConfig = new TwitterAuthConfig(TWITTER_KEY, TWITTER_SECRET);
    Fabric.with(this, new Twitter(authConfig));

    setContentView(R.layout.activity_main);

    //Initializing twitter login button
    twitterLoginButton = (TwitterLoginButton) findViewById(R.id.twitterLogin);

    //Adding callback to the button
    twitterLoginButton.setCallback(new Callback<TwitterSession>()
    {
        @Override
        public void success(Result<TwitterSession> result)
        {
            //If login succeeds passing the Calling the login method and passing Result object
            login(result);
        }

        @Override
        public void failure(TwitterException exception) {
            //If failure occurs while login handle it here
            Toast.makeText(getApplicationContext(),"Login with Twitter failure",Toast.LENGTH_LONG).show();

        }
    });

}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    //Adding the login result back to the button
    twitterLoginButton.onActivityResult(requestCode, resultCode, data);
}

//The login function accepting the result object
public void login(Result<TwitterSession> result) {

    //Creating a twitter session with result's data
    TwitterSession session = result.data;

    //Getting the username from session
    final String username = session.getUserName();

    //This code will fetch the profile image URL
    //Getting the account service of the user logged in
    Call<User> call= Twitter.getApiClient(session).getAccountService().verifyCredentials(true, false);
    call.enqueue(new Callback<User>()
    {
                @Override
                public void failure(TwitterException e)
                {
                    //If any error occurs handle it here
                }

                @Override
                public void success(Result<User> userResult)
                {
                    //If it succeeds creating a User object from userResult.data
                    User user = userResult.data;

                    //Getting the profile image url
                    String profileImage = user.profileImageUrl.replace("_normal", "");

                    //Creating an Intent
                    Intent intent = new Intent(MainActivity.this, ProfileActivity.class);

                    //Adding the values to intent
                    intent.putExtra(KEY_USERNAME,username);
                    intent.putExtra(KEY_PROFILE_IMAGE_URL, profileImage);

                    //Starting intent
                    startActivity(intent);
                }

    });
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.integrationtutorial.MainActivity">


<com.twitter.sdk.android.core.identity.TwitterLoginButton
    android:id="@+id/twitterLogin"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical" />

</RelativeLayout>

ProfileActivity.java

package com.integrationtutorial;

import android.content.Intent; 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;

public class ProfileActivity extends AppCompatActivity {

//Image Loader object
private ImageLoader imageLoader;

//NetworkImageView Ojbect
private NetworkImageView profileImage;

//TextView object
private TextView textViewUsername;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_profile);

    //Initializing views
    profileImage = (NetworkImageView) findViewById(R.id.profileImage);
    textViewUsername = (TextView) findViewById(R.id.textViewUsername);

    //Getting the intent
    Intent intent = getIntent();

    //Getting values from intent
    String username = intent.getStringExtra(MainActivity.KEY_USERNAME);
    String profileImageUrl = intent.getStringExtra(MainActivity.KEY_PROFILE_IMAGE_URL);

    //Loading image
    imageLoader = CustomVolleyRequest.getInstance(this).getImageLoader();
    imageLoader.get(profileImageUrl, ImageLoader.getImageListener(profileImage, R.mipmap.ic_launcher, android.R.drawable.ic_dialog_alert));
    profileImage.setImageUrl(profileImageUrl, imageLoader);

    //Setting the username in textview
    textViewUsername.setText("@"+username);
}
}

activity_profile.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"


android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.integrationtutorial.ProfileActivity">

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/profileImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


    <TextView
        android:id="@+id/textViewUsername"
        android:layout_margin="@dimen/activity_horizontal_margin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />



</LinearLayout>

CustomVolleyRequest.java

package com.integrationtutorial;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

import com.android.volley.Cache;
import com.android.volley.Network;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.BasicNetwork;
import com.android.volley.toolbox.DiskBasedCache;
import com.android.volley.toolbox.HurlStack;
 import com.android.volley.toolbox.ImageLoader;

public class CustomVolleyRequest {

private static CustomVolleyRequest customVolleyRequest;
private static Context context;
private RequestQueue requestQueue;
private ImageLoader imageLoader;

private CustomVolleyRequest(Context context) {
    this.context = context;
    this.requestQueue = getRequestQueue();

    imageLoader = new ImageLoader(requestQueue,
            new ImageLoader.ImageCache() {
                private final LruCache<String, Bitmap>
                        cache = new LruCache<String, Bitmap>(20);

                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }

                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
}

public static synchronized CustomVolleyRequest getInstance(Context context)     {
    if (customVolleyRequest == null) {
        customVolleyRequest = new CustomVolleyRequest(context);
    }
    return customVolleyRequest;
}

public RequestQueue getRequestQueue() {
    if (requestQueue == null) {
        Cache cache = new DiskBasedCache(context.getCacheDir(), 10 * 1024 * 1024);
        Network network = new BasicNetwork(new HurlStack());
        requestQueue = new RequestQueue(cache, network);
        requestQueue.start();
    }
    return requestQueue;
}

public ImageLoader getImageLoader() {
    return imageLoader;
}
}

Android Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.integrationtutorial">
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <meta-data
        android:name="io.fabric.ApiKey"
        android:value="KEY_HERE" />
</application>

<uses-permission android:name="android.permission.INTERNET" />
</manifest>

Solution

  • I got the same error when the Twitter application was not installed on my device.

    Desktop applications only support the oauth_callback value 'oob' /oauth/request_token

    but when the Twitter application was installed on the device, then Twitter login worked correctly.

    To get Twitter login to work if the Twitter application is not installed on a device, make the following changes to your app:

    https://apps.twitter.com/app/13917465/permissions

    Go to the "Permission" tab in your application, change Make Access to "Read, Write and Access direct messages" and also enable "Request email addresses from users" in "Additional Permissions".

    Finally, save the changes by clicking on "Update Setting".