Простой шаринг c Facebook и Twitter

        Сейчас трудно встретить сайт без кнопки «Share» (Я уже не говорю про «Like»): это быстрый и удобный способ поделиться интересной информацией с друзьями и недругами через всевозможные социальные сети. Эту же «кнопку» можно использовать и в своем Android-приложении. При этом не обязательно, чтобы приложение представляло из себя клиент Facebook'а: можно просто предоставить пользователю возможность послать себе на стенку простое сообщение, типа «Я использую Android Yorshik! Попробуй и ты!» Ну это гипотетически.
        А на деле в последнем проекте мне пришлось обеспечить пользователю возможность отравлять сообщения (и картинки) на Facebook и в Twitter о своем прогрессе, и конечно же и тут не обошлось без подводных камней (куда ж без них). Перед написанием статьи Я решил вычленить часть кода, отвечающую за шаринг, в отдельный компонент, для демонстрации работы с Facebook API и Twitter API. Но потом Остапа понесло, и в результате получился реюзабельный инструмент для простого шаринга в Facebook и Twitter (а в перспективе и в другие соцсети). Под «простым шарингом» Я подразумеваю возможность только послать сообщение или картинку. Никаких «зафрендить» или «ретвитнуть» простой шаринг не предполагает. Простой функциональности — простой интерфейс! Я попытался скрыть все сложности работы с API за красивым фасадом. Но об этом далее…

        Итак, перед нами задачи: послать сообщение на свою стену Facebook от своего имени, обновить свой статус в Twitter'е. И там, и там авторизация происходит с помощью OAuth (принципы OAuth-авторизации хорошо отражены на этой схеме). В первую очередь лезу на оф. сайты в надежде найти что-нибудь готовенькое.

    Facebook


        Facebook порадовал наличием официального Android SDK, который можно взять на GitHub'e, а также подробной инструкцией для начала использования этого SDK в своем приложении. Не могу сказать, что все в SDK мега-просто (некоторые параметры вызывают вопросы), но задачу авторизации он выполняет отлично: нам нужно только вызвать
    facebook.authorize(Activity activity, String[] permissions, DialogListener listener);
    
    и уже готовый Dialog сам появиться, позволит пользователю ввести свои данные в web-форму и в конце концов вернет нам токен авторизации, необходимый для дальнейшего общения с Facebook API. Ну а дальше надо уже с умением пользоваться методом request(...) в различных вариациях. К примеру, чтобы послать сообщение себе на стенку придется вот так вот извратиться:
    Bundle params = new Bundle();
    params.putString("message", "Android Yorshik is great!");
    facebook.request("me/feed", params, "POST");
    

        Чтобы понять, что за «me/feed» такой — придется проникнуться концепцией Open Graph Facebook'а. Но это только если вы захотите воспользоваться полной мощью доступного Facebook API.
        Первый подводный камешек встретился тут: если на девайсе уже установлен приложение-клиент Facebook, то запрос авторизации  facebook.authorize(...) приведет не к появлению диалога с WebView внутри, а к запуску этого самого приложения-клиента и открытия его формы логинизации. По плану после авторизации вы вернетесь в свое приложение так же, как и после диалога. Но, если вдруг у вас что-то хитро завязано в onResume() или onStop() вам придется учитывать, что они могут вызваться лишний раз. На одном аппарате такая форма авторизации вообще работала абы как. Так что хотелось бы на всякий случай всегда проводить логинизацию через Dialog. И такая возможность есть: дополнительный параметр Facebook.FORCE_DIALOG_AUTH поможет в этом. Вызываем:
    facebook.authorize(context, permissions, Facebook.FORCE_DIALOG_AUTH, authListener);
    и авторизация будет стабильно проходить посредством диалога.

    Twitter


        А вот Twitter официальным SDK разработчиков не одарил. Зато неофициальных предостаточно, с разными возможностями. Первое, что попало в рассмотрение:
    • Sugree Twitter Android SDK — по сути клон Facebook SDK, подогнанный под Twitter API. Однако, все что он умеет — это обеспечить авторизацию пользователя (но хотя бы присутствует готовый UI для логинизации пользователя)
    • Twitter4J — мощный набор библиотек, обширнейшая функциональность для работы с Twitter'ом (UI отсутствует)
    • JTwitter — менее обширная, чем у Twitter4J, но вполне достаточная функциональность (UI отсутствует)

        После опробирования библиотек было решено скрестить Twitter4J и UI-часть проекта Sugree. Методом проб и ошибок было обнаружено два способа осуществления авторизации.
        1) В первом случае (на данный момент именно он используется в реализованном инструменте) при регистрации своего приложения на dev.twitter.com мы оставляем поле «Callback URL» пустым. Тогда после того, как пользователь вводит авторизационные данные и нажимает «Authorize/Авторизовать» он будет переброшен на страницу с пин-кодом, который в общем-то непонятно куда вводить. Но он нужен нам, ведь только передав его на сервис Twitter'а мы сможем получить авторизационные «token и secret». Мучать лишний раз пользователя вводом подобного рода кодов — дело неблагодарное. Поэтому берем и парсим HTML-страничку и выдираем из нее этот пин-код. Как получить HTML-код загруженной в WebView страницы? Совсем не сложно:
    • создаем JavaScriptInterface, куда будет приходить HTML-код странички
      class MyJavaScriptInterface {
      	public void processHTML(String html) {
      		// process HTML
      	}
      }
      
    • добавляем этот «интерфейс» в WebView
      webView.getSettings().setJavaScriptEnabled(true);
      webView.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");
      
    • и наконец выполняем JavaScript-код после полной загрузки страницы
      webView.setWebViewClient(new MyWebViewClient());
      ...
      private class MyWebViewClient extends WebViewClient {
           ...
          @Override
          public void onPageFinished(WebView view, String url) {
              super.onPageFinished(view, url);
              browser.loadUrl("javascript:window.HTMLOUT.processHTML('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");
          }
      }

        Вот и все, извлекли пин-код — завершили авторизацию.
        2) А теперь правильный способ: в свойствах своего приложения на dev.twitter.com в поле 
    «Callback URL» вставляем любой валидный URL (н-р «http ://your.shik»). И теперь вместо парсинга страницы с пин-кодом нам нужно словить callback от Twitter'a, URL которого будет содержать параметр oauth_verifier, который мы будем использовать вместо пин-кода, чтобы получить все те же «token и secret». Такой принцип успешно реализован в данном проекте, и в ближайшем будущем Я планирую скоммуниздить реализовать такую же логику у себя.

    Simple Social Sharing


        Пару слов о созданном проекте, который был назван Simple Social Sharing. Как уже было сказано в начале, главное назначение проекта — это предоставление простого API для простого шаринга с Facebook'ом и Twitter'ом (в перспективе и с другими социальными сетями). Простой API включает в себя 4(+1) метода:
    • isAuthorized() — проверяет, авторизован ли пользователь и валидна ли текущая сессия
    • authorize() — вызывает диалог, посредством которого пользователь будет авторизоваться
    • publishMessage(...) — публикует сообщение
      • publishImage(...) — публикует изображение (только для Facebook'а)
    • logout() — очищает текущую сессию, удаляет сохраненные «token и secret»

        Диалоги будут выглядеть так:



        Все, что понадобится для работы — это:
    • фасады FacebookFacade и TwitterFacade, которые предоставляют вышеописанные методы. Создаются следующим образом:
      FacebookFacade facebook = new FacebookFacade(activity, FACEBOOK_APP_ID);
      TwitterFacade twitter = new TwitterFacade(context, TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET);
    • центры оповещения FacebookEvents и TwitterEvents, которые принимают подписки на события об авторизации (onAuthSucceed() и onAuthFail()), о публикации сообщений (onPostPublished() и onPostPublishingFailed()), о логауте (onLogoutComplete()). Можно добавлять своих слушателей, но важно не забывать их потом удалять.

        Возможно вызовет вопрос следующий метод FacebookFacade'а:
    publishMessage(String message, String link, String linkName, String linkDescription, String pictureUrl, Map<String, String> actions)

        Код и иллюстрация результата, думаю, все разъяснят:
    String message = "Look at this great App!";
    String link = "https://github.com/nostra13/Android-Simple-Social-Sharing";
    String linkName = "Use Android Simple Social Sharing in your project!";
    String linkDescription = "Also see other projects of nostra13 on GitHub!";
    String pictureUrl = "http://cdn.androidcommunity.com/wp-content/uploads/2011/01/facebook-android-logo-1.jpg";
    Map<String, String> actions = new HashMap<String, String>();
    actions.put("Android Simple Social Sharing", "https://github.com/nostra13/Android-Simple-Social-Sharing");
    
    facebook.publishMessage(message, link, linkName, linkDescription, pictureUrl, actions);
    



        Вот думаю и все. В ближайших планах проекта — переделать авторизацию на использование callback'ов, полностью избавиться от использования тяжеловесного Twitter4J. Ну а там посмотрим.

        Как всегда — исходники на GitHub. Надеюсь, инструмент пригодится и вам. Также принимаются заявки на добавление поддержки какой-нибудь другой соц.сети (Google+, к сожалению, пока не предоставил внятного SDK).

    UPD: По просьбам трудящихся. Если вы считаете, что раз на смартфоне не установлено клиента определенной соц.сети, то и шарить он в эту сеть не захочет, то можно воспользоваться самым простым способом шаринга (никаких библиотек тогда прикручивать не надо):
    final Intent intent = new Intent(Intent.ACTION_SEND);
    intent.setType(«text/plain»);
    intent.putExtra(Intent.EXTRA_TEXT, "Try Android Yorshik!");
    startActivity(Intent.createChooser(intent, getString(R.string.app_name)));
    

    Спасибо NikitaG за пример простейшего шаринга.
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 12
    • +2
      Благодарю, сударь. Только начал проникаться android-ом
      • +9
        на самом деле есть еще более простой способ реализовать share — воспользоваться встроенным диалогом

        final Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType(«text/plain»);
        intent.putExtra(Intent.EXTRA_SUBJECT, "_SUBJECT_");
        intent.putExtra(Intent.EXTRA_TEXT, "_BODY_");
        startActivity(Intent.createChooser(intent, getString(R.string.app_name)));

        Это откроет стандартный диалог со всеми подключенными share провайдерами
        • +1
          Если у юзера не установлен Твиттер клиент или Фейсбук, то их там соответственно и не будет ;)
          А приведенный автором способ позволяет не зависеть от установленного на телефоне софта
          • +3
            Зависит от задачи — иногда сомнительно предполагать, что если человек ни разу не авторизовался с телефона в TW и FB, то он, ради share будет это делать. В предложенном мной варианте мы просто даем простой способ расшарить что в два клика среди подключенных провайдеров.
            + лично мне кажется, что говорить о «Простой шаринг c Facebook и Twitter» и не упомянуть самый простой вариант это упущение
          • 0
            Поскольку постинг чего-либо в фейсбук в этой стране никому не нужен, то…
            Intent intent=new Intent(Intent.ACTION_SEND);
            intent.setType("text/plain");
            intent.putExtra(Intent.EXTRA_TEXT, "_TEXT_");
            intent.setClassName("com.vkontakte.android", "NewPostActivity");
            if(PackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)!=null){
            startActivity(intent);
            }else{
            // приложение не установлено
            }
            • +2
              Посколько Android в этой стране никому не нужен, то:
              if (androidSmartphone.isAvailable()) {
                  throwInTrash(androidSmartphone);
                  buy(«Nokia 3310»);
              }

              Или вы только для российской аудитории приложения пишете?
              • 0
                я бы не был бы настолько катигоричен на счет fb — но ваш подход понятен и тоже имеет право на жизнь как «простой share»
            • 0
              Кстати вы в курсе что share, уже deprecated?)
            • –2
              Спасибо, кэп, за статью, но сколько же уже можно писать про Hello World-ы? Моё мнение — если не о чем написать, то лучше не писать. Даже по комментам людей видно, что они и до прочтения статьи знали, как делаются настолько элементарные вещи.

              Разве в такой сложной операционке как Андроид не про что больше написать?

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