Поиск по этому блогу

понедельник, 11 марта 2013 г.

Facebook API в Android


Здравствуйте, у меня недавно появилась задача написать небольшую программу в которой будет использоваться facebook api и сегодня я хочу рассказать вам собственно как работать с этим api.

Программа будет выполнять простые действия, залогиниться в фейсбук, вывести список друзей с фотографиями, вывести детальную информацию о определенном человеке тоже с фотографией и по клику по фотографии вывести большую фотку.
Для начала нам нужно скачать само api для работы с фейсбуком, его вы можете скачать или у меня с дропбокса или с официальной страницы фейсбука для разработчиков, лучше конечно у меня скачайте потому что там непонятная фигня творится когда подключаешь версию ниже или выше.

Так же для этого туториала я использовал библиотеку для скачивания картинок, она лежит в архиве с моим SSDK так что если вы скачаете мое то проблем возникнуть не должно. Ну а если для общего развития то скачать её можно вот здесь.

Настройка проекта

Теперь когда вы скачали SDK можно приступать к настройке проекта для работы с фейсбуком. Для начала импортируйте проект facebook api 3.0 в эклипс.




Все примеры импортировать не нужно, если только вы не собираетесь разбирать их код, а только проект facebook.

Далее в вашем проекте кликаем по нему правой кнопкой и выбираем в самом низу Propertis, выбираем вкладку Android и внизу нажимаем кнопку Add и выбираем наше SDK.




Вот теперь мы добавили facebook sdk в наш проект и можем спокойно работать с ихним api.

Инициализация приложения в facebook


Далее нам нужно создать Android приложение в facebook developer tools, для этого переходим на страницу создания приложения и создаем там свое приложение, там по пунктам все, так что надеюсь сами разберетесь (:.

В итоге у вас должно получиться что-то на подобии вот такого:


Для работы приложения нам нужен App ID/API Key которым у нас является вот этот набор цифр 343214545779491, далее в проекте я буду его использовать для инициализации приложения.

Ну а теперь можно приступить к разработке.

Вход в учетную запись и вывод списка друзей


Я объедении эти два пункта для простоты понимания, так как у нас логин и вывод списка находится в одной активности будет проще понять код.

Для начала давайте опишем наш AndroidManifest, в нем нам нужно описать что мы будем использовать интернет и к каким активностям мы будем обращаться.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.facebook_api_sample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="9" />

    <uses-permission android:name="android.permission.INTERNET"/>
    
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.facebook_api_sample.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.example.facebook_api_sample.DetalsActivity"></activity>
         <activity android:name="com.example.facebook_api_sample.FullAvatarActivity"></activity>
    </application>
</manifest>


Все эти активности я опишу ниже.

Далее нам в нашем MainActivity нужно определить переменные которые будут использоваться для работы с SDK и обычные переменные для ввода и вывода контента. Так же у нас будет функция логина и функция вывода в листвью списка друзей с фотографиями через кастомный адаптер (создание кастомного адаптера я опишу в следующей статье, этот не сильно хорош...).

И так наш класс умеет:
  • Логиниться
  • Выводить список друзей с фотографиями

Смотрим как это реализовано:

MainActivity
import adapter.FriendsAdapter;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.AsyncFacebookRunner.RequestListener;
import com.facebook.android.DialogError;
import com.facebook.android.Facebook;
import com.facebook.android.Facebook.DialogListener;
import com.facebook.android.FacebookError;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
public class MainActivity extends Activity {
        
        // собственно ID приложения из facebook dev tools
        // измените на свой
        private static String APP_ID = "343214545779491"; 
        private static final String FIRST = "name";
        private static final String IMAGE = "image";
        private static final String LAST = "id";
        //массив в котором будем хранить список друзей с фотографиями
        private static ArrayList<HashMap<String, Object>> myUsers; 
        // Инициализируем класс фейсбук
        private Facebook facebook;
        //запускаем его для работы
        private AsyncFacebookRunner mAsyncRunner;
        private SharedPreferences mPrefs;
        private String FILENAME = "AndroidSSO_data";
        private int i = 0;
        private ListView listView;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                
                listView = (ListView) findViewById(R.id.listView1);
                //инициализируем наши объекты
                facebook = new Facebook(APP_ID);
                mAsyncRunner = new AsyncFacebookRunner(facebook);
                
                mPrefs = getPreferences(MODE_PRIVATE);
                //проверяем залогинен пользователь или нет
                //если залогинен то сразу выводим список друзей
                //если нет то выводим окно логина
                String access_token = mPrefs.getString("access_token", null);
                long expires = mPrefs.getLong("access_expires", 0);
                if (access_token != null) {
                        facebook.setAccessToken(access_token);
                        Log.d("FB Sessions", "" + facebook.isSessionValid());
                }
                if (expires != 0) {
                        facebook.setAccessExpires(expires);
                        getProfileInformation();
                }
                if (expires == 0) {
                        loginToFacebook();
                }
                myUsers = new ArrayList<HashMap<String, Object>>();
                listView.setOnItemClickListener(new OnItemClickListener() {

                        @Override
                        public void onItemClick(AdapterView<?> a, View v, int position, long id) {

                                HashMap<String, Object> item = myUsers.get(position);
                                String key = item.get(LAST).toString();
                                //передаем id пользователя для вывода полной информации
                                        Intent intent = new Intent(MainActivity.this, DetalsActivity.class);
                                        intent.putExtra(DetalsActivity.JSON, key);
                                        startActivity(intent);
                                
                        }
                });
        }

                /** Забираем информацию списка друзей при помощи graph anpi */
                @SuppressWarnings("deprecation")
                public void getProfileInformation() {

                        Bundle params = new Bundle();
                        params.putString("fields", "name, picture");
                        //посылаем запрос на вывод всех друзей с картинками и именами
                        mAsyncRunner.request("me/friends", params, new RequestListener() {

                                @Override
                                public void onComplete(String response, Object state) {

                                        //json который приходит с сервера
                                        String json = response;
                                        try {
                                                JSONObject profile = new JSONObject(json);
                                                JSONArray data = profile.getJSONArray("data");
                                                for (i = 0; i < data.length(); i++) {
                                                        // забираем данные из json
                                                        final String name = data.getJSONObject(i).getString("name");
                                                        final String id = data.getJSONObject(i).getString("id");
                                                        JSONObject picture = data.getJSONObject(i).getJSONObject("picture");
                                                        JSONObject picdata = picture.getJSONObject("data");
                                                        final String url = picdata.getString("url");
                                                        runOnUiThread(new Runnable() {

                                                                @Override
                                                                public void run() {

                                                                        //закидываем в массив все что получили
                                                                        HashMap<String, Object> hm;
                                                                        hm = new HashMap<String, Object>();
                                                                        hm.put(FIRST, name);
                                                                        hm.put(LAST, id);
                                                                        hm.put(IMAGE, url);
                                                                        myUsers.add(hm);
                                                                        //вытаскиваем для передачи в адаптер (так лучше не делать, мой косяк)
                                                                        String[] urls = new String[myUsers.size()];
                                                                        String[] names = new String[myUsers.size()];
                                                                        String[] indexcode = new String[myUsers.size()];
                                                                        for (int i = 0; i < myUsers.size(); i++) {
                                                                                urls[i] = (String) myUsers.get(i).get(IMAGE);
                                                                                names[i] = (String) myUsers.get(i).get(FIRST);
                                                                                indexcode[i] = (String) myUsers.get(i).get(LAST);
                                                                        }
                                                                        //передаем в адаптер для распечатки
                                                                        listView.setAdapter(new FriendsAdapter(MainActivity.this, indexcode, names, urls));
                                                                }
                                                        });
                                                }
                                        } catch (JSONException e) {
                                                e.printStackTrace();
                                        }
                                }

                                @Override
                                public void onFacebookError(FacebookError e, Object state) {

                                }

                                @Override
                                public void onFileNotFoundException(FileNotFoundException e, Object state) {

                                }

                                @Override
                                public void onIOException(IOException e, Object state) {

                                }

                                @Override
                                public void onMalformedURLException(MalformedURLException e, Object state) {

                                }
                        });
                }

                /** Функция логина в фейсбук*/
                @SuppressWarnings("deprecation")
                public void loginToFacebook() {

                        if (!facebook.isSessionValid()) {
                                facebook.authorize(this, new String[] { "email", "publish_stream" },
                                                new DialogListener() {

                                                        @Override
                                                        public void onCancel() {

                                                                //функция отмены действия
                                                        }

                                                        @Override
                                                        public void onComplete(Bundle values) {

                                                                // сохраняем данные что бы не вводить по триста раз на день
                                                                // при входе заполняем 
                                                                SharedPreferences.Editor editor = mPrefs.edit();
                                                                editor.putString("access_token", facebook.getAccessToken());
                                                                editor.putLong("access_expires", facebook.getAccessExpires());
                                                                editor.commit();
                                                                getProfileInformation();
                                                        }

                                                        @Override
                                                        public void onError(DialogError error) {

                                                                // функция ошибки
                                                        }

                                                        @Override
                                                        public void onFacebookError(FacebookError fberror) {

                                                                // функция фейсбучной ошибки
                                                        }
                                                });
                        }
                }
        }


А дальше нам в нашу разметку main.xml нужно добавить ListView для отображения контента и создать еще один файл разметки friendlist.xml который мы будем заполнять из адаптера.

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

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>
</LinearLayout>


Теперь создадим адаптер который будет скачивать фотки и выводить полученные данные. Выглядеть он будет просто.

FriendsAdapter
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.facebook_api_sample.R;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
public class FriendsAdapter extends ArrayAdapter<String> {

        private final Context context;
        private final String[] id;
        private final String[] images;
        private final String[] values;
        DisplayImageOptions options;

        public FriendsAdapter(Context runnable, String[] indexcode, String[] names, String[] urls) {

                super(runnable, R.layout.friendlist, names);
                context = runnable;
                values = names;
                images = urls;
                id = indexcode;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

                LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                View rowView = inflater.inflate(R.layout.friendlist, parent, false);
                TextView textView = (TextView) rowView.findViewById(R.id.label);
                ImageView imageView = (ImageView) rowView.findViewById(R.id.logo);
                textView.setText(values[position]);
                //
                options = new DisplayImageOptions.Builder().cacheInMemory().cacheOnDisc().bitmapConfig(
                                Bitmap.Config.RGB_565).build();
                //по заданому url скачиваем фотографию
                ImageLoader imageLoader = ImageLoader.getInstance();
                imageLoader.init(ImageLoaderConfiguration.createDefault(getContext()));
                imageLoader.displayImage(images[position], imageView, options);
                return rowView;
        }
}


Здесь у нас есть всего два метода, первый это конструктор в котором мы определяем что куда и зачем будем записывать, а второй метод у нас захватывает данные и полученные параметры обрабатывает и передает на активность.

А дальше напишем для него разметку чтобы выводить данные которые он будет скачивать и показывать. Тут у нас будет текствью с картинкой.

friendlist.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/logo"
        android:layout_width="50px"
        android:layout_height="50px"
        android:layout_marginLeft="5px"
        android:layout_marginRight="20px"
        android:layout_marginTop="5px" >
    </ImageView>

    <TextView
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30px" >
    </TextView>
</LinearLayout>


Теперь когда вы запустите проект вы увидите что-то на подобии этого:


Теперь нам нужно получать полную информацию о пользователе, переходи к следующему разделу — вывод информации о пользователе.

Вывод информации о пользователе


Что собственно тут будет, во второй активности мы будем получать айдишник пользователя и делать запрос к graph api для вывода информации о нем. Код совершенно похож на предыдущий, отличается только отсутствием функции логина и проверкой на залогинен ли человек или нет, так как это мы проверяем на первом этапе в главной активности.

DetalsActivity
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;
import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.AsyncFacebookRunner.RequestListener;
import com.facebook.android.Facebook;
import com.facebook.android.FacebookError;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
public class DetalsActivity extends Activity {

        // строчичка которая принимает айдишник из главного класса
        public static String JSON;
        // собственно ID приложения из facebook dev tools
        // измените на свой
        private static String APP_ID = "343214545779491"; 
        private TextView data;
        // Инициализируем класс фейсбук
        private final Facebook facebook = new Facebook(APP_ID);
        //запускаем его для работы
        private AsyncFacebookRunner mAsyncRunner;
        protected ImageLoader imageLoader = ImageLoader.getInstance();
        ImageView imageView;
        String url;

        /** @param key */
        @SuppressWarnings("deprecation")
        public void getAvatar(String key) {

                mAsyncRunner.request(key + "/picture?type=large&redirect=false&", new RequestListener() {

                        @Override
                        public void onComplete(final String response, Object state) {

                                runOnUiThread(new Runnable() {

                                        @Override
                                        public void run() {

                                                try {
                                                        JSONObject profile = new JSONObject(response);
                                                        JSONObject data = profile.getJSONObject("data");
                                                        String url = data.getString("url");
                                                        //по заданому url скачиваем фотографию
                                                        imageLoader.init(ImageLoaderConfiguration.createDefault(DetalsActivity.this));
                                                        imageLoader.displayImage(url, imageView);
                                                } catch (JSONException e) {
                                                        e.printStackTrace();
                                                }
                                        }
                                });
                        }

                        @Override
                        public void onFacebookError(FacebookError e, Object state) {

                        }

                        @Override
                        public void onFileNotFoundException(FileNotFoundException e, Object state) {

                        }

                        @Override
                        public void onIOException(IOException e, Object state) {

                        }

                        @Override
                        public void onMalformedURLException(MalformedURLException e, Object state) {

                        }
                });
        }

        /** @param key 
         * Получаем информацию о пользователе по его айди*/
        @SuppressWarnings("deprecation")
        public void getFriendInformation(String key) {

                //id + всеп поля которые мы хотим видеть
                mAsyncRunner.request(key + "?fields=id,name,gender,locale,birthday,hometown,languages,timezone&",
                                new RequestListener() {

                                        @Override
                                        public void onComplete(final String response, Object state) {

                                                runOnUiThread(new Runnable() {

                                                        @Override
                                                        public void run() {

                                                                //снова json который возвращает сервер
                                                                String json = response;
                                                                try {
                                                                        JSONObject profile = new JSONObject(json);
                                                                        // getting name of the user
                                                                        String json_name = profile.getString("name");
                                                                        String json_male = profile.getString("gender");
                                                                        String json_locale = profile.getString("locale");
                                                                        //
                                                                        data.setText("Name: " + json_name + "\nMale: " + json_male + "\nLocale: "
                                                                                        + json_locale);
                                                                } catch (JSONException e) {
                                                                        e.printStackTrace();
                                                                }
                                                        }
                                                });
                                        }

                                        @Override
                                        public void onFacebookError(FacebookError e, Object state) {

                                        }

                                        @Override
                                        public void onFileNotFoundException(FileNotFoundException e, Object state) {

                                        }

                                        @Override
                                        public void onIOException(IOException e, Object state) {

                                        }

                                        @Override
                                        public void onMalformedURLException(MalformedURLException e, Object state) {

                                        }
                                });
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);
                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                        finish();
                        return;
                }
                setContentView(R.layout.details_activity_layout);
                mAsyncRunner = new AsyncFacebookRunner(facebook);
                data = (TextView) findViewById(R.id.textView2);
                //
                Bundle extras = getIntent().getExtras();
                final String key = extras.getString(JSON);
                //
                imageView = (ImageView) findViewById(R.id.imageView1);
                imageView.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View v) {

                                //по клику передаем снова ключ в следующий класс 
                                Intent intent = new Intent(DetalsActivity.this, FullAvatarActivity.class);
                                intent.putExtra(FullAvatarActivity.JSON, key);
                                startActivity(intent);
                        }
                });
                //ключ для функции получения иформации
                getFriendInformation(key);
                //ключ для получения аватара
                getAvatar(key);
        }
}


И так что тут происходит? У нас есть два метода которые делают запрос на получения json с фейсбука, getFriendInformation() — делает запрос на получение инфо о юзере по его айдишнику, а getAvatar() — делает запрос на получение ссылки на аватарку пользователя по тому же айдишнику. Оба метода запускаются одновременно при старте активности. 

В onCreate() мы принимаем в переменную JSON данные которые приходят с класса MainActivity и сразу же передаем их в наши методы.

Замечание: Если вы хотите получить как можно больше данных вам нужно искать пользователей с открытыми профилями, если профиль закрыт для внешнего просмотра вы сможете просмотреть только имя с фамилией, локацию и пол.

Разметка нашего класса будет выглядеть таким образом:

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

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="24dp"
        android:layout_toRightOf="@+id/imageView1"
        android:text="no data"
        android:textSize="20sp" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@android:drawable/ic_delete" />
</RelativeLayout>


А на аппарате выглядеть оно будет вот так:


Ну а теперь нам осталось создать последнюю активность в которой мы будем выводить большую фотографию по клику на фотку в DetalsActivity.

Просмотр большого автара


Тут все идентично предыдущему пункту, все точь в точь, будем делать запрос ик в котором будем указывать айдишнк пользователя и после чего будем получать ссылку на фотографию пользователя. Вся работа с фейсбуком в принципе сводится к постоянной работе с json так что если вы не умеете работать с данной технологией сперва лучше подтяните её, а потом лезте уже в это болото.

FullAvatarActivity
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.widget.ImageView;
import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.AsyncFacebookRunner.RequestListener;
import com.facebook.android.Facebook;
import com.facebook.android.FacebookError;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
public class FullAvatarActivity extends FragmentActivity {

        public static String JSON;
        private static String APP_ID = "343214545779491"; // Replace with your App ID
        private final Facebook facebook = new Facebook(APP_ID);
        private AsyncFacebookRunner mAsyncRunner;
        protected ImageLoader imageLoader = ImageLoader.getInstance();
        ImageView imageView;

        /** @param key */
        @SuppressWarnings("deprecation")
        public void getBigImage(String key) {

                mAsyncRunner.request(key + "/picture?width=500&height=500&redirect=false&", new RequestListener() {

                        @Override
                        public void onComplete(final String response, Object state) {

                                runOnUiThread(new Runnable() {

                                        @Override
                                        public void run() {

                                                try {
                                                        JSONObject profile = new JSONObject(response);
                                                        JSONObject data = profile.getJSONObject("data");
                                                        String url = data.getString("url");
                                                        Log.v("", "" + url);
                                                        imageLoader.init(ImageLoaderConfiguration.createDefault(FullAvatarActivity.this));
                                                        imageLoader.displayImage(url, imageView);
                                                } catch (JSONException e) {
                                                        e.printStackTrace();
                                                }
                                        }
                                });
                        }

                        @Override
                        public void onFacebookError(FacebookError e, Object state) {

                        }

                        @Override
                        public void onFileNotFoundException(FileNotFoundException e, Object state) {

                        }

                        @Override
                        public void onIOException(IOException e, Object state) {

                        }

                        @Override
                        public void onMalformedURLException(MalformedURLException e, Object state) {

                        }
                });
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);
                setContentView(R.layout.big_image);
                mAsyncRunner = new AsyncFacebookRunner(facebook);
                imageView = (ImageView) findViewById(R.id.userimage);
                Bundle extras = getIntent().getExtras();
                String key = extras.getString(JSON);
                getBigImage(key);
        }
}


И разметка к классу которая состоит только из одного элемента — imageView.

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

    <ImageView
        android:id="@+id/userimage"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>


После запуска и переходов по активностям у вас должно получиться что-то на подобии вот такого:


Ссылки



--


Вот так вот можно работать с фейсбучным апи, помимо обычного конекта там еще очень много функций, но я решил рассказать именно про это так как столкнулся с таким заданием. Всем спасибо за внимание, всем хорошего дня.

Скачать с GitHub && Скачать с Dropbox