How to Use Foursquare API on Android Application

This is my second post about using Oauth enabled API on Android. This time i’ll try to explain how to use Foursquare API V2 within Android application. I built my own Android implementation for Foursquare API based on my previous  implementation for Twitter API that can be used to post Twitter status from Android. To use Foursquare API within an Android application, first you have to register your application on Foursquare to get the client id and client secret key.

I. Register application

To register your application:

    • Go to Foursquare Oauth page and login with your username and password
    • After logged in, click the ‘REGISTER A NEW CONSUMER’ button

    • Fill the registration form with your application name, application website url and the callback url. For callback url, you can use any url or string if your app is for mobile application only, for example myapp://connect

<

    • After finishing the registration , you’ll get client id and client secret key that will be used later to connect to Foursquare from Android app.

II. Android Client Code

I’ve created my own implementation to handle oauth authentification with Foursquare. It is based on my previous Twitter implementation, but with slightly modification which more simple and uses no external libraries. To access all Foursquare API endpoints, first we have to get the access token. Here is my implementation flow:
  1. Get access token by letting user grant access to the app using a webview based authentication dialog
  2. Save access token on shared preferences
  3. Use the access token to access Foursquare API endpoints

I’ve included a sample project in this tutorial that can be downloaded on my github repo here. I’ll explain how to use my implementation based on the sample project. In my sample project, i create three classes used to handle authentication and connection to Foursquare: FoursquareApp.java (handle oauth authentification), FoursquareSession.java (save access token on shared preferences) and FoursquareDialog.java (webview authentication dialog).

Main.java

public class Main extends Activity {
	private FoursquareApp mFsqApp;
	private ListView mListView;
	private NearbyAdapter mAdapter;
	private ArrayList<FsqVenue> mNearbyList;
	private ProgressDialog mProgress;

	public static final String CLIENT_ID = "your client id";
	public static final String CLIENT_SECRET = "your client secret";

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

        setContentView(R.layout.main);

        final TextView nameTv 		= (TextView) findViewById(R.id.tv_name);
        Button connectBtn 			= (Button) findViewById(R.id.b_connect);
        final EditText latitudeEt	= (EditText) findViewById(R.id.et_latitude);
        final EditText longitudeEt	= (EditText) findViewById(R.id.et_longitude);
        Button goBtn				= (Button) findViewById(R.id.b_go);
        mListView					= (ListView) findViewById(R.id.lv_places);

        mFsqApp 		= new FoursquareApp(this, CLIENT_ID, CLIENT_SECRET);

        mAdapter 		= new NearbyAdapter(this);
        mNearbyList		= new ArrayList<FsqVenue>();
        mProgress		= new ProgressDialog(this);

        mProgress.setMessage("Loading data ...");

        if (mFsqApp.hasAccessToken()) nameTv.setText("Connected as " + mFsqApp.getUserName());

        FsqAuthListener listener = new FsqAuthListener() {
        	@Override
        	public void onSuccess() {
        		Toast.makeText(Main.this, "Connected as " + mFsqApp.getUserName(), Toast.LENGTH_SHORT).show();
        		nameTv.setText("Connected as " + mFsqApp.getUserName());
        	}

        	@Override
        	public void onFail(String error) {
        		Toast.makeText(Main.this, error, Toast.LENGTH_SHORT).show();
        	}
        };

        mFsqApp.setListener(listener);

        //get access token and user name from foursquare
        connectBtn.setOnClickListener(new OnClickListener() {
        	@Override
        	public void onClick(View v) {
        		mFsqApp.authorize();
        	}
        });

        //use access token to get nearby places
        goBtn.setOnClickListener(new OnClickListener() {
        	@Override
        	public void onClick(View v) {
        		String latitude  = latitudeEt.getText().toString();
        		String longitude = longitudeEt.getText().toString();

        		if (latitude.equals("") || longitude.equals("")) {
        			Toast.makeText(Main.this, "Latitude or longitude is empty", Toast.LENGTH_SHORT).show();
        			return;
        		}

    			double lat	= Double.valueOf(latitude);
    			double lon	= Double.valueOf(longitude);

        		loadNearbyPlaces(lat, lon);
        	}
        });
    }

    private void loadNearbyPlaces(final double latitude, final double longitude) {
    	mProgress.show();

    	new Thread() {
    		@Override
    		public void run() {
    			int what = 0;

    			try {

    				mNearbyList = mFsqApp.getNearby(latitude, longitude);
    			} catch (Exception e) {
    				what = 1;
    				e.printStackTrace();
    			}

    			mHandler.sendMessage(mHandler.obtainMessage(what));
    		}
    	}.start();
    }

    private Handler mHandler = new Handler() {
    	@Override
    	public void handleMessage(Message msg) {
    		mProgress.dismiss();

    		if (msg.what == 0) {
    			if (mNearbyList.size() == 0) {
    				Toast.makeText(Main.this, "No nearby places available", Toast.LENGTH_SHORT).show();
    				return;
    			}

    			mAdapter.setData(mNearbyList);
    			mListView.setAdapter(mAdapter);
    		} else {
    			Toast.makeText(Main.this, "Failed to load nearby places", Toast.LENGTH_SHORT).show();
    		}
    	}
    };
}

The example above shows how to authenticate user to get access token, display the webview authentication dialog then use the access token to access Foursquare API endpoint which in this example is to get the nearby venues.

Line 8-9: First, replace the CLIENT_ID and CLIENT_SECREET with your app client id and client secret
Line 24: Create an instance of FoursquareApp class and pass the CLIENT_ID and CLIENT_SECRET as parameters
Line 32: Check if user has access token (already authorized the app before) using hasAccessToken
method.
Line 34: Setup listener to handle authorization result event (success or fail)
Line 53: Display the authentication dialog
Line 87: Get nearby venues, an example how to access Foursquare API endpoint. The getNearbyVenue method was defined in FourquareApp.java

FoursquareApp.java

public static final String CALLBACK_URL = "myapp://connect";
private static final String AUTH_URL = "https://foursquare.com/oauth2/authenticate?response_type=code";
private static final String TOKEN_URL = "https://foursquare.com/oauth2/access_token?grant_type=authorization_code";
private static final String API_URL = "https://api.foursquare.com/v2";

Line 1: Replace the CALLBACK_URL with your callback url set before on web settings.
Line 4: API_URL is the root url for Foursquare API endpoint. Do not change this url unless Foursqure make changes on their API url.

public ArrayList<FsqVenue> getNearby(double latitude, double longitude) throws Exception {
		ArrayList<FsqVenue> venueList = new ArrayList<FsqVenue>();

		try {
			String ll 	= String.valueOf(latitude) + "," + String.valueOf(longitude);
			URL url 	= new URL(API_URL + "/venues/search?ll=" + ll + "&oauth_token=" + mAccessToken);

			Log.d(TAG, "Opening URL " + url.toString());

			HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

			urlConnection.setRequestMethod("GET");
			urlConnection.setDoInput(true);
			urlConnection.setDoOutput(true);

			urlConnection.connect();

			String response		= streamToString(urlConnection.getInputStream());
			JSONObject jsonObj 	= (JSONObject) new JSONTokener(response).nextValue();

			JSONArray groups	= (JSONArray) jsonObj.getJSONObject("response").getJSONArray("groups");

			int length			= groups.length();

			if (length > 0) {
				for (int i = 0; i < length; i++) {
					JSONObject group 	= (JSONObject) groups.get(i);
					JSONArray items 	= (JSONArray) group.getJSONArray("items");

					int ilength 		= items.length();

					for (int j = 0; j < ilength; j++) {
						JSONObject item = (JSONObject) items.get(j);

						FsqVenue venue 	= new FsqVenue();

						venue.id 		= item.getString("id");
						venue.name		= item.getString("name");

						JSONObject location = (JSONObject) item.getJSONObject("location");

						Location loc 	= new Location(LocationManager.GPS_PROVIDER);

						loc.setLatitude(Double.valueOf(location.getString("lat")));
						loc.setLongitude(Double.valueOf(location.getString("lng")));

						venue.location	= loc;
						venue.address	= location.getString("address");
						venue.distance	= location.getInt("distance");
						venue.herenow	= item.getJSONObject("hereNow").getInt("count");
						venue.type		= group.getString("type");

						venueList.add(venue);
					}
				}
			}
		} catch (Exception ex) {
			throw ex;
		}

		return venueList;
	}

To access Foursquare API endpoint, use standard HTTPURLConnection class, where the url depends on what endpoint you want to access. Complete list of Foursquare API endpoints can be found here.

facebooktwittergoogle_plusredditpinterestlinkedinmailby feather

Comments

    • says

      That means the json response has no ‘address’ field. You can check if the field exists using: jsonObj.isNull(‘address’) to prevent parsing error.

      • Andy says

        So how do you fix this JSON error? Am i just inputting invalid lat/long coordinates, and thus it isn’t returning anything?

        • Andy says

          For instance I type in
          Long: -84.3566371
          Latitude: 33.7744506
          (Atlanta, GA)

          but it just keeps giving me “failed to load nearby places”, with a similar JSON error as listed above

          • Andy says

            What’s also weird is that if i paste the returned URL from logcat into a browser it gives me correct stuff back like:

            {“meta”:{“code”:200,”errorType”:”deprecated”,”errorDetail”:”This endpoint will stop returning groups in the future. Please use a current version, see http://bit.ly/lZx3NU.”},”notifications”:[{"type":"notificationTray","item":{"unreadCount":0}}],”response”:{“groups”:[{“type”:”nearby”,”name”:”Nearby”,”items”:

  1. Andy says

    Ahhh! now i know what you mean, I guess some foursquare entities don’t have an address field. In case anyone wants to know, I put in this line of code in to fix it

    if(!jlocation.isNull(“address”)){
    venue.address = jlocation.getString(“address”);
    }

  2. TheVaan says

    To fix the distance problem (shows any time “0m”) change line 60 in NearbyAdapter.java from:

    holder.mDistanceTxt.setText(formatDistance(venue.direction));

    to:

    holder.mDistanceTxt.setText(formatDistance(venue.distance));

    Out of this you can delete all parts in the sourcecode that deal with “direction”.

  3. PUSHPENDRA KUNTAL says

    Sir, i have done this. now i want to write code for checkin. please help me, how can i write code for checkin of a user.

  4. vennila vaithi says

    Hi Lorenz,
    I tried your application , But am getting access token token failed and failed to load NearByValues, I only changed the Client_id and Client_secret and callback url . I got the following error in my logCat

    03-30 15:31:08.382: W/System.err(516): java.io.IOException: Received authentication challenge is null
    03-30 15:31:08.382: W/System.err(516): at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.doRequestInternal(HttpURLConnectionImpl.java:1694)
    03-30 15:31:08.391: W/System.err(516): at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.doRequest(HttpURLConnectionImpl.java:1649)
    03-30 15:31:08.391: W/System.err(516): at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1153)
    03-30 15:31:08.391: W/System.err(516): at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:253)
    03-30 15:31:08.391: W/System.err(516): at net.londatiga.fsq.FoursquareApp.getNearby(FoursquareApp.java:214)
    03-30 15:31:08.391: W/System.err(516): at net.londatiga.fsq.Main$5.run(Main.java:121)

    pls give me whats wrong in this?

  5. Dhaval says

    hi,

    i am use your code in my app. but i got error when redirect after login.

    error like “you have not permission to open this page”

  6. giles ian says

    what changes do i need to make in the above project if i dont have website … i only have android app

  7. victor yew says

    Hi Lorenz,

    I’ve got the access token successfully BUT I am connected as a NULL. How do I get self username? Thx

  8. says

    I have the same problem as victor, connected as null, and failed to get the file in the logcat, how to solve this problem, Please help Lorenz. Thanks for the great work.

    • says

      and change connection type as below

      RL url = new URL(API_URL + “/users/self?oauth_token=”
      + mAccessToken + “&v=201208201″);

      Log.d(TAG, “Opening URL ” + url.toString());

      HttpGet httpRequest = null;

      httpRequest = new HttpGet(url.toURI());
      HttpClient httpclient = new DefaultHttpClient();
      HttpResponse httpresponse = (HttpResponse) httpclient
      .execute(httpRequest);

      HttpEntity entity = httpresponse.getEntity();
      BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(
      entity);
      InputStream input = bufHttpEntity.getContent();

      String response = streamToString(input);

    • says

      Hi Eray,

      Thanks for the solution, currently thats not a mandatory, you can still use the API without versioning.

      Not passing the v parameter will currently return the oldest version of the API. In the future, the default will be to use the most recent API (instead of current default, which is to use the oldest API). Over time, we will phase out support for legacy behavior.

      But it is recommended to use versioning for compatibility in the future API update. The real problem with my codes was in HttpConnection (see my answer to danzil). The solution is to remove the “urlConnection.setDoOutput(true);” line or replace the HttpConnection with HttpClient for making connection with http as you described in your solution code..

  9. says

    Dear Lorenz,

    herenow parameter is no longer returned from API.
    There are :

    “stats”: {
    “checkinsCount”: 285,
    “usersCount”: 181,
    “tipCount”: 1
    },

    and
    “beenHere”: {
    “count”: 0
    },

  10. anonymous says

    Halo Om Lorenz saya mau tanya donk.
    Kok setiap get nearby places failed mulu y?
    ni logcat ny om :

    09-07 16:35:21.619: W/System.err(23522): org.json.JSONException: No value for groups
    09-07 16:35:21.629: W/System.err(23522): at org.json.JSONObject.get(JSONObject.java:354)
    09-07 16:35:21.629: W/System.err(23522): at org.json.JSONObject.getJSONArray(JSONObject.java:544)
    09-07 16:35:21.639: W/System.err(23522): at net.londatiga.fsq.FoursquareApp.getNearby(FoursquareApp.java:221)
    09-07 16:35:21.639: W/System.err(23522): at net.londatiga.fsq.Main$5.run(Main.java:122)
    09-07 16:35:21.759: W/asset(23522): deep redirect failure from 0×01030046 => 0×02060015, defStyleAttr=0×01010084, defStyleRes=0×01030022, style=0×00000000

    mohon bantuannya om. :D

  11. anonymous says

    09-07 16:35:21.619: W/System.err(23522): org.json.JSONException: No value for groups
    09-07 16:35:21.629: W/System.err(23522): at org.json.JSONObject.get(JSONObject.java:354)
    09-07 16:35:21.629: W/System.err(23522): at org.json.JSONObject.getJSONArray(JSONObject.java:544)
    09-07 16:35:21.639: W/System.err(23522): at net.londatiga.fsq.FoursquareApp.getNearby(FoursquareApp.java:221)
    09-07 16:35:21.639: W/System.err(23522): at net.londatiga.fsq.Main$5.run(Main.java:122)
    09-07 16:35:21.759: W/asset(23522): deep redirect failure from 0×01030046 => 0×02060015, defStyleAttr=0×01010084, defStyleRes=0×01030022, style=0×00000000

  12. Androider says

    Hi Lorenz, first thanks a lot for posting this. It helped me a lot. But I got some kind of an error in the pop up layout. It says :-
    Connecting failed
    This app has a configuration problem and was unable to connect to your foursquare account.

    By the I gave internet permission on the android manifest file.

    Please help me.

    Thank you

  13. Grace says

    Hi
    I am trying to register as new consumer with the link posted but it’s not working. Can any one please tell me the stepsto get my ClientID and Client Secret.
    I am not able to locate it on Foursquare api website.

    Thanks alot

  14. yash says

    hello all,
    at this point they(foursquare have removed firstname,lasname detail on json,and also removed “groups” field . )
    So when u start app please debug on eclipse or any IDE and then try to hit URL on webbrowser u will see json response and check that response.

  15. esquiter says

    hello, I tried to run this example, but not JSON comes complete, when I run the url in the browser works normally.

    what’s going?

  16. Claudia Bauger says

    Hey hi,
    I has been set all the required value as you said.But i don’t know, i’m getting “Authorization failed” Exception.
    Required value:-
    1.Client ID
    2.Secrete key
    3.CALLBACK URI :-( https://www.jhakas.com/redirect_uri)

    Please your help will be very appreciable

    thank you in advance

  17. Claudia Bauger says

    Hey hi,
    I has been set the required value as you said.But i don’t know, I’m getting “Authorization failed ” message.

    Required changes:
    1.Client ID
    2.Secrete key
    3.Call back URI(https://www.jhakas.com/redirect_uri)

    Please you help will be appreciable

    thank you

  18. Claudia Bauger says

    Hey hi ,
    First of all i just want to say thank for your great work. this is claudia again with new error, Last one error, some how I has been solved.

    Now when the get the palces…It gives a JSONException “No value for groups ” What does that means…..

    Please help me out

    Thanks

  19. Undang says

    Om, help me ni ko failed to get nearby places terus ni di logcat nya “org.json.JSONException: No value for groups” ..
    gimana ya ?

  20. Undang says

    Om, help me ni selalu “failed to load nearby places”,

    error di logcatnya begini “org.json.JSONException: No value for groups”.

    help me donk

  21. ankit sharma says

    hi,

    I am unable to get the near by places as it says ‘failed to load the nearby places” with the following logcat :

    04-19 10:31:10.830: D/FoursquareApi(10756): Opening URL https://api.foursquare.com/v2/venues/search?ll=43.89765,77.123455&oauth_token=H0SURUVPG2DKXLSSTRBLBQ2OT4UKMQDAOFFBOVUJSZYT0R0C&v=20130419
    04-19 10:31:13.342: W/System.err(10756): org.json.JSONException: No value for groups
    04-19 10:31:13.342: W/System.err(10756): at org.json.JSONObject.get(JSONObject.java:354)
    04-19 10:31:13.342: W/System.err(10756): at org.json.JSONObject.getJSONArray(JSONObject.java:544)
    04-19 10:31:13.342: W/System.err(10756): at com.example.nearbyplaces.FoursquareApp.getNearby(FoursquareApp.java:217)
    04-19 10:31:13.352: W/System.err(10756): at com.example.nearbyplaces.MainActivity$5.run(MainActivity.java:108)

  22. Dhruv says

    I am done with this foursquare integration. If i want to add setting which means in foursquare site “Settings->Sharing with other networks” through my mobile application. How can i do that?

    Please Reply me as soon as possible.

    Thanks in Advance.

  23. says

    Hi
    I am unable to use your library properly.

    Your mentioned Foursquare Oauth link doesnt exist anymore !
    I have created a Test app in foursquare but unable to use it with the library !Am i missing anything

Leave a Reply

Your email address will not be published. Required fields are marked *