Android: Instagram photos of a particular user

Asked

Viewed 522 times

0

Setting:

In my app I want to show the photos of a user. I am authenticating, I have access to the token and I can log in with user and password but after logging in it says that I am not allowed to open this page.

Code:

Photosactivity.java

public static final String CLIENT_ID = "seu_id";
public static final String CLIENT_SECRET = "seu_secret";
public static final String CALLBACK_URL = "callback";
String url ="https://instagram.com/oauth/authorize?" +"response_type=token" + "&redirect_uri=" + CALLBACK_URL+"&scope=basic"+"&client_id=" + CLIENT_ID ;

WebView webview;

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

    ActionBar bar = getActionBar();
    bar.setDisplayHomeAsUpEnabled(true);

    WebView webview = (WebView)findViewById(R.id.webView2);

    webview.setWebViewClient(new WebViewClient() {

        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            String fragment = "#access_token=";
            int start = url.indexOf(fragment);
            if (start > -1) {

                // You can use the accessToken for api calls now.
                String accessToken = url.substring(start + fragment.length(), url.length());

                Log.v(TAG, "OAuth complete, token: [" + accessToken + "].");
                Log.i(TAG, "" +accessToken);
Toast.makeText(PhotosActivity.this, "Token: " + accessToken, Toast.LENGTH_SHORT).show();
            }
        }
    });

    webview.loadUrl(url);

}
  • To CALLBACK_URL is the link from a page of your server that ends the Oauth process by getting the correct token? Or are you using a fake url just to extract the token from the url? Another question, registered this CALLBACK_URL on your Instagram developer account?

  • I am using a fake URL and registered this URL there in the Instagram developer account yes. The error I am getting is {"code": 403, "error_type": "OAuthForbiddenException", "error_message": "Implicit authentication is disabled"} Actually I would like to display the public photos of a user without showing this Instagram login screen.

  • Ah, I get it... you’re using Implicit Flow, I didn’t know there was such a form of authentication. Take a look at the developer panel of Instagram, if the checkbox of Disable implicit OAuth is unchecked for your app.

  • So, right after I posted the answer to your question, I went there and cleared that option and it worked. But funny that I’m testing on AVD and on a tablet from Samsung. On AVD is "correct", but on my tablet my App closes.

  • Put the USB cable and check on Logcat which was the exception that occurred.

  • You know how to upload photos of a particular Instagram user without having to do this authentication, or better, that this authentication runs in the background without having to type user/password?

  • You can only do this if the profile is public (https://help.instagram.com/116024195217477/). I used the http://instagram.com/developer/endpoints/users/#get_users_media_recent, the access_token in case it was my API_KEY.

  • Yes, the idea is only for public profile. It would be as you exemplify how you use this method?

  • Okay, I’m going to take a code that I used for the same purpose and create a response.

Show 4 more comments

1 answer

1

I had the same need as you, access the images of a public profile on Instagram on Android App.

But one thing I did differently was create a WebService that from time to time queries the Media API and updates the database. But the core of the access should be very similar.

I did it because I don’t know if it’s worth leaving the Client ID in the app, for security reasons, someone can spy on the requests and catch the Client ID that your application is using, being able to make this Client ID become invalid.

The code is a little more complex, because I tried to normalize the consumption of various social media API’s, I will put only the specific part of Instagram.

To mount the URI to access the WebService from instagram I did:

public String getUri(String instagramUserId, String token, int amount) throws UnsupportedEncodingException {
    StringBuilder uri = new StringBuilder("https://api.instagram.com/v1");

    // instagramUserId é uma variável local com o ID do usuário de perfil público
    // Pode ser obtido nesse site: http://jelled.com/instagram/lookup-user-id
    // token é o Client ID do aplicativo
    // amount é a quantidade de registros que devem ser retornadas

     uri.append("/users/").append(instagramUserId)
        .append("/media/recent?client_id=").append(URLEncoder.encode(token, "UTF-8"))
        .append("&count=").append(Integer.toString(amount));

    return uri.toString();
}

With this URI I made one HttpRequest to the Instagram endpoint, as below:

@Override
public List<JSONObject> fetchInstagram(String instagramUserId, String token, int amount) {
    try {
        String uri = getUri(instagramUserId, token, amount);

        if(uri == null) {
            return Collections.EMPTY_LIST;
        }

        // Inicializa um cliente Http
        HttpClient httpClient = HttpClientBuilder.create().build();

        // Especifica o método a ser executado, GET como especificado pela documentacao do Instagram
        HttpGet get = new HttpGet(uri);

        // Definindo o Charset da resposta, a fim de evitar problemas com encoding
        // Definindo que o cliente aceita codificação gzip, para reduzir o gasto de banda do dispositivo.
        get.addHeader("Accept-Encoding", "gzip");
        get.addHeader("Accept-Charset", "UTF-8");

        System.out.println("Making request to " + uri);

        // Executa a requisicao e espera pela resposta
        HttpResponse response = httpClient.execute(get);

        // Se o Instagram nao respondeu com codigo 200 (OK), entao loga o erro
        if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
            System.out.println(EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")));
            return null;
        }

        // Extrai a resposta em formato String
        String responseString = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8"));

        // Retorna a lista de registros de midia do usuario
        return parseResponse(responseString);
    } catch (MalformedURLException | ProtocolException e) {
        e.printStackTrace();
        return null;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

// Aqui poderia ser retornado o próprio JSONArray com os registros
public List<JSONObject> parseResponse(String response) {
    // Transforma a resposta String em JSON, para poder manipular
    JSONObject jsonResponse = new JSONObject(response);

    // Atributo do JSON que contem a lista de registros obtidos do usuario
    JSONArray registros = jsonResponse.getJSONArray("data");
    List<JSONObject> objetos = new ArrayList<JSONObject>();

    for(int i = 0; i < registros.length(); ++i) {
        JSONObject o = registros.getJSONObject(i);

        // Faz uma logica com o registro em si, filtragem, normalizacao, ou outro qualquer

        objetos.add(o);
    }

    return registros;
}

To use, just do:

public void callInstagram() {
    String token = "SEU_CLIENT_D";
    String instagramUserId = "USER_ID";

    int amount = 100;

    List<JSONObject> registros = fetchInstagram(instagramUserId, token, amount);

    // Processa os registros, levando em conta o tipo e as resolucoes das midias.
}

In this solution I ended up using the API of HttpComponents Apache (to use the Httpclient, Httpget, and Httpclientbuilder class), which can be obtained at this address: http://hc.apache.org/. There is the migration to Android at this address: http://hc.apache.org/httpcomponents-client-4.3.x/android-port.html.

An example of Instagram’s JSON response is:

{
    "data": [{
        "comments": {
            "data": [],
            "count": 0
        },
        "caption": {
            "created_time": "1296710352",
            "text": "Inside le truc #foodtruck",
            "from": {
                "username": "kevin",
                "full_name": "Kevin Systrom",
                "type": "user",
                "id": "3"
            },
            "id": "26621408"
        },
        "likes": {
            "count": 15,
            "data": [{
                "username": "mikeyk",
                "full_name": "Mike Krieger",
                "id": "4",
                "profile_picture": "..."
            }, {...subset of likers...}]
        },
        "link": "http://instagr.am/p/BWrVZ/",
        "user": {
            "username": "kevin",
            "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_3_75sq_1295574122.jpg",
            "id": "3"
        },
        "created_time": "1296710327",
        "images": {
            "low_resolution": {
                "url": "http://distillery.s3.amazonaws.com/media/2011/02/02/6ea7baea55774c5e81e7e3e1f6e791a7_6.jpg",
                "width": 306,
                "height": 306
            },
            "thumbnail": {
                "url": "http://distillery.s3.amazonaws.com/media/2011/02/02/6ea7baea55774c5e81e7e3e1f6e791a7_5.jpg",
                "width": 150,
                "height": 150
            },
            "standard_resolution": {
                "url": "http://distillery.s3.amazonaws.com/media/2011/02/02/6ea7baea55774c5e81e7e3e1f6e791a7_7.jpg",
                "width": 612,
                "height": 612
            }
        },
        "type": "image",
        "users_in_photo": [],
        "filter": "Earlybird",
        "tags": ["foodtruck"],
        "id": "22721881",
        "location": {
            "latitude": 37.778720183610183,
            "longitude": -122.3962783813477,
            "id": "520640",
            "street_address": "",
            "name": "Le Truc"
        }
    },
    {
        "videos": {
            "low_resolution": {
                "url": "http://distilleryvesper9-13.ak.instagram.com/090d06dad9cd11e2aa0912313817975d_102.mp4",
                "width": 480,
                "height": 480
            },
            "standard_resolution": {
                "url": "http://distilleryvesper9-13.ak.instagram.com/090d06dad9cd11e2aa0912313817975d_101.mp4",
                "width": 640,
                "height": 640
            },
        "comments": {
            "data": [{
                "created_time": "1279332030",
                "text": "Love the sign here",
                "from": {
                    "username": "mikeyk",
                    "full_name": "Mikey Krieger",
                    "id": "4",
                    "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1242695_75sq_1293915800.jpg"
                },
                "id": "8"
            },
            {
                "created_time": "1279341004",
                "text": "Chilako taco",
                "from": {
                    "username": "kevin",
                    "full_name": "Kevin S",
                    "id": "3",
                    "profile_picture": "..."
                },
                "id": "3"
            }],
            "count": 2
        },
        "caption": null,
        "likes": {
            "count": 1,
            "data": [{
                "username": "mikeyk",
                "full_name": "Mikeyk",
                "id": "4",
                "profile_picture": "..."
            }]
        },
        "link": "http://instagr.am/p/D/",
        "created_time": "1279340983",
        "images": {
            "low_resolution": {
                "url": "http://distilleryimage2.ak.instagram.com/11f75f1cd9cc11e2a0fd22000aa8039a_6.jpg",
                "width": 306,
                "height": 306
            },
            "thumbnail": {
                "url": "http://distilleryimage2.ak.instagram.com/11f75f1cd9cc11e2a0fd22000aa8039a_5.jpg",
                "width": 150,
                "height": 150
            },
            "standard_resolution": {
                "url": "http://distilleryimage2.ak.instagram.com/11f75f1cd9cc11e2a0fd22000aa8039a_7.jpg",
                "width": 612,
                "height": 612
            }
        },
        "type": "video",
        "users_in_photo": null,
        "filter": "Vesper",
        "tags": [],
        "id": "363839373298",
        "user": {
            "username": "kevin",
            "full_name": "Kevin S",
            "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_3_75sq_1295574122.jpg",
            "id": "3"
        },
        "location": null
    },
   ]
}

You will need to see which fields of each object that make up the answer is needed, and take into consideration that for some media types (image in this case), it provides multiple resolutions, which can be used on different devices (tablets or smartphone).

  • Your solution seems to be very good. But for those who are starting, which is my case, I can not understand very well. It would be interesting to clarify your solution so that other people, both with more experience or little experience understand better.

  • Okay, I’ll try the one simplified and put more comments.

  • Okay @fricks, I got an update. I simplified, commented on some parts, put an example of using the methods and put a reference to the library I used in this example.

  • I haven’t had any success with it yet @Wakim!

  • @fricks, try to specify your question better I try to detail more.

  • I don’t know how to organize your code inside my Photosactivity and I didn’t understand anything about the Httpcomponents API that you commented because I never used.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.