AndroidSocialNetworks — удобная работа с социальными сетями


AndroidSocialNetworks — это библиотека для Android, которая делает работу с соц. сетями проще. Если вы когда-либо пробовали работать с соц. сетями, то знаете насколько это тяжело. Нужно прочитать документацию для каждой соц. сети, скачать и подключить SDK или стороннюю библиотеку, позаботиться о жизненном цикле http запросов. AndroidSocialNetwork должна сделать вашу жизнь проще, она содержит общий интерфейс для Facebook, Twitter, LinkedIn и Google Plus — просто сбилдите SocialNetworkManager с помощью SocialNetworkManager.Build -> добавьте его в FragmentManager -> настройте AndroidManifest.xml -> работайте с настроенными соц. сетями. Вы сможете делать login, постить обновление статуса, постить фотки, добавлять / удалять друзей.

Как пользоваться


Для начала нам нужно инициализировать SocialNetworkManager, это делается с помощью SocialNetworkManager.Builder. SocialNetworkManager это Fragment с retainedInstance(true).
Это необходимо для того, чтобы была возможность следить за жизненным циклом.
После того как мы инициализировали SocialNetworkManager, его необходимо добавить в FragmentManager. Учтите, что для совместимости необходимо использовать SupportFragmentManager.

mSocialNetworkManager = (SocialNetworkManager) getFragmentManager().findFragmentByTag(SOCIAL_NETWORK_TAG);

if (mSocialNetworkManager == null) {
    mSocialNetworkManager = SocialNetworkManager.Builder.from(getActivity())
                .twitter(<api_token>, <api_secret>)
                .linkedIn(<api_token>, <api_secret>, "r_basicprofile+rw_nus+r_network+w_messages")
                .facebook()
                .googlePlus()
                .build();
    getFragmentManager().beginTransaction().add(mSocialNetworkManager, SOCIAL_NETWORK_TAG).commit();
}

Поскольку добавление фрагмента – это транзакция, мы не можем сразу начать использовать SocialNetworkManager, для этого предусмотрен callback — SocialNetworkManager.OnInitializationCompleteListener.

mSocialNetworkManager.setOnInitializationCompleteListener(this);

Если нам, например, нужно показывать, подключен ли Twitter, обновлять UI нужно именно в onSocialNetworkManagerInitialized.

Каждый метод запроса может получать listener, а может и не получать, во 2 случае будет вызван глобальный, если он установлен:
Устанавливаем глобальный listener на Login
@Override
public void onSocialNetworkManagerInitialized() {
    super.onSocialNetworkManagerInitialized();

    for (SocialNetwork socialNetwork : mSocialNetworkManager.getInitializedSocialNetworks()) {
        socialNetwork.setOnLoginCompleteListener(this);
    }
}


Вызываем логин для LinkedIn
mSocialNetworkManager.getLinkedInSocialNetwork().requestLogin();

Результат получаем в глобальном callback.
@Override
public void onLoginSuccess(int socialNetworkID) {

}

@Override
public void onError(int socialNetworkID, String requestID, String errorMessage, Object data) {

}

Если мы не хотим пользоваться глобальными callbacks, можем использовать локальные:
mSocialNetworkManager.getGooglePlusSocialNetwork().requestLogin(new DemoOnLoginCompleteListener());

private class DemoOnLoginCompleteListener implements OnLoginCompleteListener {
    @Override
    public void onLoginSuccess(int socialNetworkID) {

    }

    @Override
    public void onError(int socialNetworkID, String requestID, String errorMessage, Object data) {

    }
}

Такой механизм можно использовать не только для requestLogin, все основные методы поддерживают 2 типа задания callback.

Своя реализация соц. сети

Если вам не хватает доступных соц. сетей, и вы хотите добавить поддержу другой, то можете сделать это с помощью метода addSocialNetwork(SocialNetwork socialNetwork).
Учтите, что делать это нужно в onSocialNetworkManagerInitialized. Также учтите, что ID вашей соц. сети должен быть уникальным. 1, 2, 3, 4 — уже зарезервированы.

Доступные методы



Полный список



Поддержка соц. сетями



Как это работает


Как можно понять, SocialNetworkManager — это фрагмент (из support v4 для совместимости). Это нужно для того, чтобы можно было удобно отслеживать жизненный цикл приложения. Он также сделан retainedInstance(true) для того, чтобы сетевые запросы нормально переживали изменения lifecycle…

SocialNetworkManager.Builder всего лишь подготавливает Bundle с параметрами.
public SocialNetworkManager build() {
    Bundle args = new Bundle();

    if (!TextUtils.isEmpty(twitterConsumerKey) && !TextUtils.isEmpty(twitterConsumerSecret)) {
        args.putString(PARAM_TWITTER_KEY, twitterConsumerKey);
        args.putString(PARAM_TWITTER_SECRET, twitterConsumerSecret);
    }

    if (!TextUtils.isEmpty(linkedInConsumerKey) && !TextUtils.isEmpty(linkedInConsumerSecret)
                    && !TextUtils.isEmpty(linkedInPermissions)) {
        args.putString(PARAM_LINKEDIN_KEY, linkedInConsumerKey);
        args.putString(PARAM_LINKEDIN_SECRET, linkedInConsumerSecret);
        args.putString(PARAM_LINKEDIN_PERMISSIONS, linkedInPermissions);
    }

    if (facebook) {
        args.putBoolean(PARAM_FACEBOOK, true);
    }

    if (googlePlus) {
        args.putBoolean(PARAM_GOOGLE_PLUS, true);
    }

    SocialNetworkManager socialNetworkManager = new SocialNetworkManager();
    socialNetworkManager.setArguments(args);
    return socialNetworkManager;
}

Внутри SocialNetworkManager все инициализированные соц. сети хранятся в HashMap
private Map<Integer, SocialNetwork> mSocialNetworksMap = new HashMap<Integer, SocialNetwork>();

В callbacks lifecycle мы проходим по всем соц. сетям и пробрасываем значения:
public void onStop() {
    …
    for (SocialNetwork socialNetwork : mSocialNetworksMap.values()) {
        socialNetwork.onStop();
    }
}

Каждая соц. сеть должна наследоваться от абстрактного класса SocialNetwork.

Нужно переопределить метод getID(), именно по возвращаемому значению этого метода соц. сети и будут различаться. В своих реализациях, я для удобства делал ID public, чтобы можно было использовать socialNetwork.getID() в switch.
public class GooglePlusSocialNetwork extends SocialNetwork …
    public static final int ID = 3;

Методы lifecycle не обязательны для переопределения, только по необходимости.

Для реализации методов requestLogin, requestPerson и т.д. необходимо переопределять методы с callbackами. Это необходимо из-за поддержки как глобальных, так и локальных listeners.

Callbackи хранятся в Maps
protected Map<String, SocialNetworkListener> mGlobalListeners = new HashMap<String, SocialNetworkListener>();
protected Map<String, SocialNetworkListener> mLocalListeners = new HashMap<String, SocialNetworkListener>();

Когда мы добавляем глобальный callback, он добавляется в mGlobalListeners, далее при любом вызове без callback мы вызываем метод с callback, передавая null.

public void requestSocialPerson(String userID) {
    requestSocialPerson(userID, null);
}

Метод с callback регистрирует listener.
public void requestSocialPerson(String userID, OnRequestSocialPersonCompleteListener onRequestSocialPersonCompleteListener) {
    registerListener(REQUEST_GET_PERSON, onRequestSocialPersonCompleteListener);
}


Реализация registerListener довольно проста:
private void registerListener(String listenerID, SocialNetworkListener socialNetworkListener) {
    if (socialNetworkListener != null) {
        mLocalListeners.put(listenerID, socialNetworkListener);
    } else {
        mLocalListeners.put(listenerID, mGlobalListeners.get(listenerID));
    }
}

Сетевые запросы

Для выполнения сетевых запросов используется либо методы SDK:
Request request = Request.newMeRequest(currentSession, new Request.GraphUserCallback() {
    @Override
    public void onCompleted(GraphUser me, Response response) {
        …

request.executeAsync();

либо AsyncTasks, не стоит пугаться асинк тасков, если вы помните, то мы используем их в Fragmentе в retainedInstance(true). Хорошая статья на эту тему: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

Важно


  • Библиотека не заботиться о состоянии вашего приложения и жизненого цикла, вы должны делать это сами!
  • Если Вы используете Google Plus, добавьте этот код в вашу активити:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    
        /**
         * This is required only if you are using Google Plus, the issue is that there SDK
         * require Activity to launch Auth, so library can't receive onActivityResult in fragment
         */
        Fragment fragment = getSupportFragmentManager().findFragmentByTag(BaseDemoFragment.SOCIAL_NETWORK_TAG);
        if (fragment != null) {
                fragment.onActivityResult(requestCode, resultCode, data);
            }
        }
    



Ссылка на библиотеку: https://github.com/antonkrasov/AndroidSocialNetworks
Sample application: AndroidSocialNetworks APIDemos
Поделиться публикацией

Комментарии 14

    +4
    Резонный вопрос вам уже задали в Google Play — как насчёт контакта? Или вы решили поддерживать только мировых международных лидеров?)
      0
      Я планирую добавить поддержку VK в будущем, для начала нужно сделать библиотеку модульной, потому что нет смысле добавлять поддержку VK всем, не хочется делать моструозный комбайн, вот над этим и размышляю. На данный момент, можно добавить поддерку самому, заимплементив SocialNetwork.
      –1
      Крутяк, а В контакте есть? )
        +1
        Пока нет, смотрите мой ответ выше. Но я работаю над этим :)
        +1
        Кое-какие вопросы/предложения:
        1) Зачем в dependencies signpost-core, если вы его не используете? Просто не увидел его в импортах в ваших файлах.
        2) Для TW вы используете twitter4j, хотя, по сути, только реализовали авторизацию и публикацию сообщений. Только один twitter4j-core-4.0.1.jar весит около 300кб. Я бы рекомендовал использовать signpost для авторизации (он весит 50кб), а для публикации сообщений обычные http запросы. Понимаю, что сейчас многие уже и не смотрят на размер итогового .apk. Но всё же…
        3) Быть может стоит разнести логику по соц. сетям в разные классы/пакеты. Я про классы из com.androidsocialnetworks.lib.impl.*. Взять хотя бы TwitterSocialNetwork. У вас слишком много внутренних классов. Рекомендовал бы отдельный пакет сделать (например com.androidsocialnetworks.lib.impl.tw), а там по разным классам разнести всё это. Потому что, если вы будете наращивать функционал вашей библиотеки, при этом продолжая в одном классе всё писать, то получится слишком толстый контроллер.

        p.s. хотелось бы ещё VK видеть в списке.
          0
          1) Точно не помню, но вроде linkedin-j-android.jar зависит от signpost-core.
          2) Пока возможно, но при расширении и наращивании функционала, будет довольно тяжело самому все реализовывать, + нужно будет следить за обновлениями в API twitterа. Я думаю проблему размера нужно решить с помощью proguard и модульности, не всем нужны все 4 соц сети, но руки все никака не дойдут.
          3) Я согласен, но думаю пока это делать рано, нужно будет подумать о том как можно это лучше реализовать, сейчас все не очень удобно.

          Насчет VK я уже понял, работаю над этим :)
          0
          Можете объяснить чем эта библиотека лучше Scribe? Там поддержка соц. сетей пошире будет, вконтактик есть :)
            0
            Насколько я могу судить, в Scribe только авторизация реализована.
              +1
              Верно, но и в авторизации есть разница, Scribe не позволяет авторизироваться через Facebook App например, если он установлен. А это намного более удобно для конечного пользователя, чем OAuth и постоянный ввод пароля.
                0
                Зато не тянет за собой 200 килобайтную либу FB SDK )
                  0
                  Каждый делает выбор :) В моем текущем проекте, для которого это либа изначально писалась, это было совсем не принципиально. Плюс, если вы вдруг захотите не только авторизацию, то все равно Facebook SDK прийдется тянуть.
            0
            Он также сделан retainedInstance(true) для того, чтобы сетевые запросы нормально переживали изменения lifecycle…

            Почему же не использовали Loader'ы?
              0
              1) Потому что я считаю, что Loader'ы предназначены не для этого, их задача работать с базой.
              2) Их не очень удобно использовать.
              0
              offtop: забавно бы смотрелось сокращение вашей библиотеки до «AsocialNetworks»

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

              Самое читаемое