Статьи

Работа с API Facebook в приложении Cordova

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

Создать приложение для Facebook

Сначала создайте приложение на веб-сайте разработчиков Facebook . Наведите указатель мыши на меню « Мои приложения» и выберите « Добавить новое приложение» . Это откроет модальное окно, которое позволяет вам выбрать платформу для вашего приложения. В этом случае мы будем развертывать на устройстве Android, поэтому выберите Android в модальном окне.

новое приложение facebook

Введите имя для приложения и нажмите кнопку « Создать новый идентификатор приложения Facebook» .

новый идентификатор Facebook

Вам будет задан вопрос, является ли приложение тестовой версией существующего приложения, оставьте его по умолчанию « нет» . Другой вариант — категория, выберите приложения для страниц, затем нажмите кнопку « Создать идентификатор приложения» .

категория приложения

Далее вам будет предложено добавить SDK Facebook в ваш проект. Нам не нужно делать это для нашего приложения, поэтому продолжайте прокручивать страницу, пока не найдете раздел Расскажите нам о своем проекте Android . Введите com.yourname.appname в качестве имени пакета, а затем com.yourname.appname.MainActivity в качестве имени класса активности по умолчанию, заменив его соответствующими значениями для вашего проекта.

Подробности проекта

Как только это будет завершено, нам нужно добавить ключевые хэши разработки и выпуска. Они проверяют подлинность вашего приложения, так что Facebook уверен, что вы являетесь автором приложения, а запросы к их API поступают от вас.

Хеши развития

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

keytool -genkey -v -keystore cordova-social.keystore -alias cordovaSocial -keyalg RSA -keysize 2048 -validity 10000 

Получить хеш из хранилища ключей:

 keytool -exportcert -alias androiddebugkey -keystore cordova-social.keystore | openssl sha1 -binary | openssl base64 

Это должно попросить вас пароль. Просто используйте тот же пароль, который использовался при создании хранилища ключей. После ввода он должен вернуть хеш для этого хранилища ключей. Скопируйте и вставьте его в поле хэшей разработки.

Нажмите « Далее» и обновите страницу. Ваше приложение должно появиться в списке, когда вы нажимаете на меню Мои приложения . Запишите идентификатор приложения, так как он понадобится нам позже, когда мы установим плагин Facebook.

Сборка приложения

Теперь мы готовы построить приложение. Установите Ionic (который мы будем использовать для создания нашего приложения) с помощью следующей команды:

 npm install -g ionic 

Создайте новое пустое приложение:

 ionic start your_app_name blank cd your_app_name 

Добавьте платформу Android:

 ionic platform add android 

Установка зависимостей

Далее нам нужно установить следующие плагины:

Кордова-Plugin-Whitelist

Позволяет нам контролировать, к каким доменам приложение может отправлять запросы.

Кордова-Plugin-камера

Позволяет нам использовать камеру устройства для захвата фотографий.

org.apache.cordova.file-Transfer

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

Примечание . Мы используем старую версию этого плагина, поскольку последняя версия несовместима с текущей версией Cordova (5.0.0) на момент написания этой статьи. Если вы читаете это в будущем, вы можете попробовать использовать следующую команду: cordova plugin add cordova-plugin-file-transfer и посмотреть, работает ли он для вас. В противном случае используйте команду ниже.

PhoneGap-facebook-плагин

Официальный плагин Facebook, используемый для выполнения различных операций с API Facebook.

Установите плагины с помощью следующих команд:

 cordova plugin add cordova-plugin-whitelist cordova plugin add cordova-plugin-camera cordova plugin add org.apache.cordova.file-transfer cordova plugin add https://github.com/Wizcorp/phonegap-facebook-plugin --variable APP_ID=YOUR_FACEBOOK_APP_ID --variable APP_NAME=YOUR_APP_NAME 

Как только это будет завершено, нам нужно установить внешнюю зависимость под названием Angular Local Storage . Это позволяет нам работать с локальным хранилищем для кэширования данных в нашем приложении. Вы можете установить Angular Local Storage через Bower с помощью следующей команды:

 bower install angular-local-storage --save 

Ionic устанавливает компоненты Bower в каталог www / lib . Вы можете проверить место сохранения, открыв файл .bowerrc в корневом каталоге проекта.

 { "directory": "www/lib" } 

Связывание файлов

На данный момент мы будем в основном работать внутри каталога www . Откройте файл index.html в этом каталоге.

Ссылка на скрипт Angular Local Storage ниже файла ionic.bundle.js .

 <script src="lib/ionic/js/ionic.bundle.js"></script> <script src="lib/angular-local-storage/dist/angular-local-storage.min.js"></script> 

Ниже файла app.js ссылки на следующие скрипты:

 <script src="js/app.js"></script> <!--services--> <script src="js/services/RequestsService.js"></script> <script src="js/services/CameraService.js"></script> <!--controllers--> <script src="js/controllers/LoginController.js"></script> <script src="js/controllers/DialogController.js"></script> <script src="js/controllers/UserDetailsController.js"></script> 

Позже я объясню, что делает каждый из этих сценариев. Сервисные сценарии предназначены для выполнения HTTP-запросов и в качестве оболочки для плагина Camera. Скрипты контроллера предназначены для разных страниц приложения.

Измените <body> (и его содержимое), чтобы иметь следующую разметку. <ion-nav-view> — это место, где различные страницы будут загружены позже.

 <body ng-app="starter"> <ion-nav-view></ion-nav-view> </body> 

Добавление страниц

Откройте файл www / js / app.js и добавьте LocalStorageModule . Это позволяет нам использовать localStorageService для хранения и извлечения данных из локального хранилища.

 angular.module('starter', ['ionic', 'LocalStorageModule']) 

Под методом .run добавьте конфигурацию приложения, вызвав метод config . Этот метод принимает функцию обратного вызова, где мы передаем $stateProvider и $urlRouterProvider чтобы мы могли указать маршрут для различных страниц в приложении.

 .run(function($ionicPlatform) { ... }) .config(function($stateProvider, $urlRouterProvider) { $stateProvider .state('app', { url: '/app', abstract: true, templateUrl: 'templates/menu.html', }) .state('app.login', { url: '/login', views: { 'menuContent': { templateUrl: 'templates/login.html' } } }) .state('app.post-status', { url: '/post-status', views: { 'menuContent': { templateUrl: 'templates/post-status.html' } } }) .state('app.post-photo', { url: '/post-photo', views: { 'menuContent': { templateUrl: 'templates/post-photo.html' } } }) .state('app.send-message', { url: '/send-message', views: { 'menuContent': { templateUrl: 'templates/send-message.html' } } }) .state('app.user-details', { url: '/user-details', views: { 'menuContent': { templateUrl: 'templates/user-details.html' } } }); $urlRouterProvider.otherwise('/app/login'); }); 

Взломать код Сначала у нас есть абстрактное состояние, называемое app . Это похоже на родительское состояние, где все остальные состояния, определенные ниже, наследуются от него. В этом случае мы устанавливаем templateUrl в templates/menu.html который является путем к основному шаблону, в котором будут наследоваться все представления.

 .state('app', { url: '/app', abstract: true, templateUrl: 'templates/menu.html', }) 

Создайте основной шаблон в каталоге www / templates и назовите его menu.html , добавив следующее.

 <ion-side-menus> <ion-side-menu-content> <ion-nav-bar class="bar-positive nav-title-slide-ios7"> <ion-nav-back-button class="button-clear"><i class="icon ion-ios7-arrow-back"></i> Back</ion-nav-back-button> </ion-nav-bar> <ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view> </ion-side-menu-content> <ion-side-menu side="left"> <header class="bar bar-header bar-positive"></header> <ion-content class="has-header"> <ion-list> <ion-item nav-clear menu-close href="#/app/login"> login & logout </ion-item> <ion-item nav-clear menu-close href="#/app/post-status"> post status </ion-item> <ion-item nav-clear menu-close href="#/app/post-photo"> post photo </ion-item> <ion-item nav-clear menu-close href="#/app/send-message"> send message </ion-item> <ion-item nav-clear menu-close href="#/app/user-details"> user details </ion-item> </ion-list> </ion-content> </ion-side-menu> </ion-side-menus> 

Этот шаблон использует <ion-side-menus> который отображает боковое меню в левой части приложения. По умолчанию это свернуто, которое показывает меню бургера.

<ion-nav-view> отображает текущий вид. Атрибут name должен быть указан, потому что это то место, к которому привязано представление.

 <ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view> 

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

 <ion-content class="has-header"> <ion-list> <ion-item nav-clear menu-close href="#/app/login"> login & logout </ion-item> <ion-item nav-clear menu-close href="#/app/post-status"> post status </ion-item> <ion-item nav-clear menu-close href="#/app/post-photo"> post photo </ion-item> <ion-item nav-clear menu-close href="#/app/send-message"> send message </ion-item> <ion-item nav-clear menu-close href="#/app/user-details"> user details </ion-item> </ion-list> </ion-content> 

Возвращаясь к файлу www / js / app.js , мы затем определяем состояния для разных страниц. Все эти состояния используют объявленное ранее абстрактное состояние. На это указывает префикс каждого маршрута с app. , url — это URL-адрес, по которому отображается представление. Для маршрута входа в систему мы указали только /login . Но поскольку мы используем абстрактное состояние, фактическим URL-адресом будет /app/login поскольку значением для url назначенным ранее абстрактному состоянию, является /app . Затем у нас есть объект views в котором мы указываем имя представления, в котором отображается шаблон. Для этого требуется свойство templateUrl которое содержит путь к шаблону. Тот же шаблон используется во всех других маршрутах.

  .state('app.login', { url: '/login', views: { 'menuContent': { templateUrl: 'templates/login.html' } } }) .state('app.post-status', { url: '/post-status', views: { 'menuContent': { templateUrl: 'templates/post-status.html' } } }) .state('app.post-photo', { url: '/post-photo', views: { 'menuContent': { templateUrl: 'templates/post-photo.html' } } }) .state('app.send-message', { url: '/send-message', views: { 'menuContent': { templateUrl: 'templates/send-message.html' } } }) .state('app.user-details', { url: '/user-details', views: { 'menuContent': { templateUrl: 'templates/user-details.html' } } }); 

Наконец, мы указываем страницу по умолчанию:

 $urlRouterProvider.otherwise('/app/login'); 

Сервисы

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

Камера Сервис

Первый сервис, который является CameraService , служит контейнером для вызовов API, которые мы можем сделать с помощью плагина Camera. Создайте файл CameraService.js в каталоге js / controllers и добавьте следующее.

 (function(){ angular.module('starter') .service('CameraService', ['$q', CameraService]); function CameraService($q){ var me = this; me.options = { quality: 80, targetWidth: 300, targetHeight: 300, correctOrientation: true }; function getPicture(){ var q = $q.defer(); navigator.camera.getPicture( function(result){ q.resolve(result); }, function(err){ q.reject(err); }, me.options ); return q.promise; } return { getPicture: getPicture } } })(); 

Разбивая код, мы сначала оборачиваем все в «выражение немедленно выполняемой функции». Это предотвращает конфликт с другими скриптами.

 (function(){ ... })(); 

Далее мы указываем модуль, к которому принадлежит этот сервис, и что этот сервис зависит от сервиса Angular $q . Это позволяет нам запускать функции асинхронно.

  angular.module('starter') .service('CameraService', ['$q', CameraService]); 

Затем это передается в качестве аргумента функции CameraService .

 function CameraService($q){ } 

Внутри функции мы устанавливаем переменную me в качестве псевдонима для текущего контекста и используем ее для установки параметров плагина камеры.

 var me = this; me.options = { quality: 80, targetWidth: 300, targetHeight: 300, correctOrientation: true }; 

Далее у нас есть функция getPicture . Эта функция вызывается каждый раз, когда нам нужно сделать фотографию. Это возвращает обещание, которое означает, что мы можем использовать метод then чтобы передать функцию, которую мы хотим выполнить, как только пользователь выберет фотографию.

 function getPicture(){ var q = $q.defer(); navigator.camera.getPicture( function(result){ q.resolve(result); }, function(err){ q.reject(err); }, me.options ); return q.promise; } return { getPicture: getPicture } 

Служба запросов

Служба запросов отправляет HTTP-запросы на сервер приложений. Приложение, которое мы создаем, имеет серверный компонент, который позволяет нам проверять ответ, возвращаемый API Facebook, и загружать фотографии на сервер. Создайте файл RequestService.js в каталоге js / services и добавьте следующее:

 (function(){ angular.module('starter') .service('RequestsService', ['$http', '$q', '$ionicLoading', '$timeout', '$ionicPopup', RequestsService]); function RequestsService($http, $q, $ionicLoading, $timeout, $ionicPopup){ var base_url = 'http://YOUR-SERVER-URL'; var me = this; me.timeout = { value: 20000, message: 'Please check your internet connection and re-launch the app' }; function requestTimeout(deferred){ var timer = $timeout(function(){ $ionicLoading.hide(); $ionicPopup.alert({ 'title': me.timeout.message }); deferred.reject(); }, me.timeout.value); return timer; }; function sendData(data){ var deferred = $q.defer(); var timer = requestTimeout(deferred); $ionicLoading.show(); $http.post(base_url + '/data', {'data' : data}) .success(function(response){ $timeout.cancel(timer); $ionicLoading.hide(); $ionicPopup.alert({ 'title': response.message }); deferred.resolve(response); }) .error(function(data){ deferred.reject(); }); return deferred.promise; }; function uploadPhoto(photo_url, params){ var deferred = $q.defer(); var options = new FileUploadOptions(); options.fileKey = 'file'; options.fileName = photo_url.substr(photo_url.lastIndexOf('/') + 1).split('?')[0]; options.mimeType = 'image/jpeg'; options.params = params; var ft = new FileTransfer(); ft.upload( photo_url, base_url + '/upload', function(result){ deferred.resolve(result); }, function(err){ deferred.reject(err); }, options ); return deferred.promise; } return { sendData: sendData, uploadPhoto: uploadPhoto }; } })(); 

Разбивая код, мы сначала импортируем несколько сервисов, встроенных в Angular и Ionic.

 angular.module('starter') .service('RequestsService', ['$http', '$q', '$ionicLoading', '$timeout', '$ionicPopup', RequestsService]); 
  • $http : Позволяет нам делать HTTP-запросы.
  • $ionicLoading : показывает загрузчик gif каждый раз, когда мы делаем HTTP-запросы.
  • $timeout : способ реализации setTimeout Angular.
  • $ionicPopup : версия окна оповещения Ionic.

Установите настройки для базового URL для отправки запросов и тайм-аутов

 var base_url = 'http://YOUR-SERVER-URL'; var me = this; me.timeout = { value: 20000, message: 'Please check your internet connection and re-launch the app' }; 

Функция requestTimeout позволяет нам предупреждать пользователя, когда запрос достигает заданного значения времени ожидания. Это работает, останавливая время ожидания, как только мы получим ответ от запроса.

 function requestTimeout(deferred){ var timer = $timeout(function(){ $ionicLoading.hide(); $ionicPopup.alert({ 'title': me.timeout.message }); deferred.reject(); }, me.timeout.value); return timer; }; 

Функция sendData позволяет нам отправлять данные на сервер. Для этого приложения мы используем его для отправки пользовательских данных на сервер, а затем сохранить их в базе данных. Эта функция принимает данные, отправленные в качестве своего параметра, а затем использует службу $http Angular для отправки запроса POST на сервер. Как только мы получаем успех в качестве ответа, мы отменяем тайм-аут, чтобы не вызывать вызов $ionicPopup.alert . Как и с другими функциями, мы используем сервис $q чтобы превратить его в асинхронный вызов функции. Позже, когда мы начнем вызывать эти функции из контроллера, вы увидите множество вызовов метода then() запускаемых всякий раз, когда мы вызываем deferred.resolve(response) . Затем мы можем передать функцию в метод then() в котором мы можем получить доступ к response возвращенному из запроса.

 function sendData(data){ var deferred = $q.defer(); var timer = requestTimeout(deferred); $ionicLoading.show(); $http.post(base_url + '/data', {'data' : data}) .success(function(response){ $timeout.cancel(timer); $ionicLoading.hide(); $ionicPopup.alert({ 'title': response.message }); deferred.resolve(response); }) .error(function(data){ deferred.reject(); }); return deferred.promise; }; 

Функция uploadPhoto позволяет нам загружать фотографии на сервер. Это принимает photo_url который в основном является FILE_URI возвращаемым плагином камеры после того, как фотография была сделана. params содержит любые пользовательские данные, которые мы хотим передать в отношении файла.

 function uploadPhoto(photo_url, params){ var deferred = $q.defer(); var options = new FileUploadOptions(); options.fileKey = 'file'; options.fileName = photo_url.substr(photo_url.lastIndexOf('/') + 1).split('?')[0]; options.mimeType = 'image/jpeg'; options.params = params; var ft = new FileTransfer(); ft.upload( photo_url, me.upload_url + '/upload', function(result){ deferred.resolve(result); }, function(err){ deferred.reject(err); }, options ); return deferred.promise; }; 

Контроллеры

Контроллеры в основном используются для прослушивания событий и реагирования на них. Пример — когда пользователь нажимает кнопку. Контроллер отвечает за обработку этого конкретного события.

Авторизоваться

Контроллер входа обрабатывает все события, которые происходят на странице входа в приложение. Создайте файл LoginController.js в каталоге js / controllers и добавьте следующее:

 (function(){ angular.module('starter') .controller('LoginController', ['$scope', 'localStorageService', 'RequestsService', LoginController]); function LoginController($scope, localStorageService, RequestsService){ var me = this; me.updateLoginStatus = function(){ facebookConnectPlugin.getLoginStatus( function(response){ if(response.status === 'connected'){ me.logged_in = true; }else{ me.logged_in = false; } }, function(err){ me.logged_in = false; alert('Error while trying to check login status'); RequestsService.sendData(err); } ); }; $scope.fbLogin = function(){ facebookConnectPlugin.login(['email'], function(response){ me.logged_in = true; alert('logged in successfully'); alert(JSON.stringify(response.authResponse)); RequestsService.sendData(response.authResponse); localStorageService.set('user.id', response.authResponse.userID); localStorageService.set('user.access_token', response.authResponse.accessToken); }, function(err){ RequestsService.sendData(err); alert('an error occured while trying to login. please try again.'); }); }; $scope.fbLogout = function(){ facebookConnectPlugin.logout( function(response){ alert(JSON.stringify(response)); RequestsService.sendData(response); }, function(err){ alert(JSON.stringify(err)); RequestsService.sendData(err); } ); }; } })(); 

Как и сервисы, мы можем импортировать сервисы внутри контроллеров. На этот раз мы используем два новых сервиса: $scope и localStorageService .

 angular.module('starter') .controller('LoginController', ['$scope', 'localStorageService', 'RequestsService', LoginController]); 

Вот краткое описание того, что они делают:

  • $scope : используется для присоединения данных или событий к текущей странице.
  • localStorageService : используется для сохранения и извлечения данных из локального хранилища.

Внутри контроллера мы прикрепляем функцию updateLoginStatus . Эта функция проверяет, активен ли текущий сеанс Facebook через объект facebookConnectPlugin доступный глобально из плагина Facebook. Затем мы обновляем значение свойства logged_in на основе результата. Это переключает переключатель в представлении о том, отображать ли кнопку входа или выхода из системы.

 me.updateLoginStatus = function(){ facebookConnectPlugin.getLoginStatus( function(response){ if(response.status === 'connected'){ me.logged_in = true; }else{ me.logged_in = false; } }, function(err){ me.logged_in = false; alert('Error while trying to check login status'); RequestsService.sendData(err); } ); }; 

Присоедините функцию fbLogin к текущей области. Это выполняется, когда пользователь нажимает кнопку входа в систему .

 $scope.fbLogin = function(){ ... } 

Внутри функции fbLogin мы вызываем метод login из объекта facebookConnectPlugin , открывая окно входа в Facebook. Если приложение Facebook установлено и пользователь в настоящий момент вошел в систему, все, что ему нужно сделать, это согласиться с разрешениями приложения для аутентификации приложения. В этом случае разрешение передается по email . Это означает, что приложение будет иметь доступ к адресу электронной почты пользователя. Как только пользователь соглашается с разрешениями, вызывается функция обратного вызова успеха, в противном случае вызывается функция обратного вызова ошибки. Когда пользователь соглашается, ответ содержит пользовательские данные. Мы используем localStorageService чтобы сохранить их в локальном хранилище, а затем используем RequestsService чтобы отправить его на сервер.

 facebookConnectPlugin.login(['email'], function(response){ me.logged_in = true; alert('logged in successfully'); alert(JSON.stringify(response.authResponse)); localStorageService.set('user.id', response.authResponse.userID); localStorageService.set('user.access_token', response.authResponse.accessToken); RequestsService.sendData(response.authResponse); }, function(err){ RequestsService.sendData(err); alert('an error occured while trying to login. please try again.'); }); 

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

Логин в фейсбук

Функция fbLogout используется для выхода из Facebook. Это разрушает текущий сеанс пользователя.

 $scope.fbLogout = function(){ facebookConnectPlugin.logout( function(response){ me.logged_in = false; alert(JSON.stringify(response)); RequestsService.sendData(response); }, function(err){ alert(JSON.stringify(err)); RequestsService.sendData(err); } ); }; 

Теперь мы можем добавить вид входа в систему. Представления сохраняются в каталоге шаблонов . Создайте файл login.html внутри этого каталога и добавьте следующее.

 <ion-view title="Login & Logout" ng-controller="LoginController as login_ctrl" ng-init="login_ctrl.updateLoginStatus()"> <ion-nav-buttons side="left"> <button menu-toggle="left" class="button button-icon icon ion-navicon"></button> </ion-nav-buttons> <ion-content class="has-header padding"> <button class="button button-positive button-block" ng-hide="login_ctrl.logged_in" ng-click="fbLogin()"> Login with Facebook </button> <button class="button button-assertive button-block" ng-show="login_ctrl.logged_in" ng-click="fbLogout()"> Logout </button> </ion-content> </ion-view> 

Все представления начинаются с <ion-view> . В приведенном выше коде мы передаем заголовок (показанный в заголовке страницы) и контроллер, который использует это представление. Директива ng-init выполняет updateLoginStatus после инициализации этого представления. Это означает, что он сразу же запускается, когда пользователь переходит на страницу входа.

<ion-content> определяет содержимое страницы. В этом случае все, что нам нужно, это кнопка для входа в Facebook. Мы добавили к этой кнопке атрибут ng-click и в качестве значения fbLogin функцию fbLogin определенную ранее в loginController . ng-click — это встроенная в Angular директива, которая в основном используется для прослушивания событий щелчка в определенном элементе. Это означает, что когда кнопка нажата, она выполняет функцию fbLogin , то же самое верно и для кнопки, используемой для выхода из Facebook. Директивы ng-hide и ng-show скрывают и отображают эти две кнопки в зависимости от того, вошел ли пользователь в систему или нет.

Данные пользователя

UserDetailsController отображает информацию о зарегистрированном пользователе. Создайте файл UserDetailsController.js в каталоге www / js и добавьте следующее.

 (function(){ angular.module('starter') .controller('UserDetailsController', ['$scope', 'localStorageService', 'RequestsService', UserDetailsController]); function UserDetailsController($scope, localStorageService, RequestsService){ var me = this; $scope.user = null; me.getUserInfo = function(){ var user_id = localStorageService.get('user.id'); facebookConnectPlugin.api( user_id + "/?fields=id,email,first_name,last_name,gender,age_range", ['public_profile', 'email'], function (response) { alert(JSON.stringify(response)); RequestsService.sendData(response); $scope.user = response; }, function (error) { alert("Failed: " + error); } ); }; } })(); 

Внутри контроллера мы устанавливаем для user значение null поэтому информация о пользователе отображается только при нажатии кнопки, вызывая функцию getUserInfo .

 me.getUserInfo = function(){ ... } 

Внутри функции мы получаем идентификатор пользователя Facebook из локального хранилища.

 var user_id = localStorageService.get('user.id'); 

И используйте его для получения информации о пользователе от Graph API. Мы только пытаемся получить основную информацию без регистрации приложения через API.

Чтобы сделать запрос к API Graph, вызовите метод api и передайте четыре аргумента. Первый путь, по которому сделан запрос. Поскольку мы работаем с пользовательскими данными, мы используем идентификатор Facebook пользователя в качестве базы и указываем, какую информацию мы хотим получить, предоставляя fields в качестве параметра запроса.

Затем мы передаем разделенный запятыми список всех полей, которые мы хотим получить. Если вы хотите получить полный список доступных полей, ознакомьтесь с Справочником пользователя API Graph Facebook .

Второй аргумент — это массив, содержащий различные разрешения, которые пользователь должен утвердить. Здесь нам требуются пользователи public_profile и email . Вы можете увидеть полный список разрешений на странице справки по разрешениям . Обратите внимание, что если в конкретном разрешении указано, что для его просмотра требуется Facebook, вы не сможете его использовать, даже если вы разработчик приложения.

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

 facebookConnectPlugin.api( user_id + "/?fields=id,email,first_name,last_name,gender,age_range", ['public_profile', 'email'], function (response) { alert(JSON.stringify(response)); RequestsService.sendData(response); $scope.user = response; }, function (error) { alert("Failed: " + error); } ); 

Вот представление сведений о пользователе ( www / templates / user-details.html ). Вы можете видеть, что мы использовали директиву ng-if чтобы проверить, установлена ​​ли переменная user . Если это так, то отображаются данные пользователя.

 <ion-view title="User Details" ng-controller="UserDetailsController as details_ctrl"> <ion-nav-buttons side="left"> <button menu-toggle="left" class="button button-icon icon ion-navicon"></button> </ion-nav-buttons> <ion-content class="has-header padding"> <button class="button button-positive" ng-hide="user" ng-click="details_ctrl.getUserInfo()"> Show User Details </button> <div class="card"> <div class="item item-text-wrap" ng-if="user"> <ul> <li>id: {{ user.id }}</li> <li>email: {{ user.email }}</li> <li>name: {{ user.first_name }} {{ user.last_name }}</li> <li>gender: {{ user.gender }}</li> <li>age_range: {{ user.age_range.min }}</li> </ul> </div> </div> </ion-content> </ion-view> 

Вот как должна выглядеть страница с информацией о пользователе:

данные пользователя

диалог

DialogController обрабатывает события на страницах, которые используют диалоги Facebook, такие как диалог подачи, отправки и обмена. Создайте DialogController.js в каталоге js / controllers и добавьте следующее.

 (function(){ angular.module('starter') .controller('DialogController', ['$scope', 'RequestsService', 'CameraService', DialogController]); function DialogController($scope, RequestsService, CameraService){ var me = this; me.base_uploads_url = 'YOUR-SERVER-URL/uploads'; $scope.postStatus = function(){ var dialog_options = { method: 'feed', link: me.url, caption: me.caption }; facebookConnectPlugin.showDialog(dialog_options, function(response){ alert('posted!'); RequestsService.sendData(response); }, function(err){ RequestsService.sendData(err); alert('something went wrong while trying to post'); }); }; $scope.capturePhoto = function(){ CameraService.getPicture().then(function(imageURI) { alert(imageURI); me.photo = imageURI; }, function(err) { alert(err); }); }; $scope.postPhoto = function(){ var dialog_options = { method: "feed", name: me.caption, message: me.caption, caption: me.caption, description: me.caption }; var photo_data = { 'caption': me.caption }; RequestsService.uploadPhoto(me.photo, photo_data).then(function(response){ var res = JSON.parse(response.response); dialog_options.picture = me.base_uploads_url + res.image_url; facebookConnectPlugin.showDialog(dialog_options, function (response) { RequestsService.sendData(response); alert(JSON.stringify(response)) }, function (response) { RequestsService.sendData(response); alert(JSON.stringify(response)) } ); }, function(response){ alert(JSON.stringify(response)); }); }; $scope.sendMessage = function(){ facebookConnectPlugin.showDialog( { method: "send", link: me.url }, function (response) { RequestsService.sendData(response); alert(JSON.stringify(response)) }, function (response) { RequestsService.sendData(response); alert(JSON.stringify(response)) } ); }; } })(); 

Разбивая код, внутри контроллера находится URL для загрузки фотографий. Именно здесь RequestsService отправляет захваченное фото.

 me.base_uploads_url = 'YOUR-SERVER-URL/uploads/'; 

Далее у нас postStatus функция postStatus когда пользователь нажимает кнопку для публикации статуса Facebook.

 $scope.postStatus = function(){ ... } 

Вместо того, чтобы публиковать сообщения напрямую с помощью API Graph, мы используем диалог подачи в Facebook Для этого требуется объект, содержащий тип диалога, URL-адрес для включения в сообщение и текст для отображения в качестве заголовка.

 var dialog_options = { method: 'feed', //type of dialog link: me.url, //URL to include in the post caption: me.caption //the text which will show as the title of the link }; 

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

 facebookConnectPlugin.showDialog(dialog_options, function(response){ alert('posted!'); RequestsService.sendData(response); }, function(err){ RequestsService.sendData(err); alert('something went wrong while trying to post'); }); 

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

статус публикации

Присоедините функцию для открытия приложения камеры по умолчанию на устройстве к области $scope . Это использует CameraService для запуска приложения камеры для открытия. Как только пользователь заканчивает фотографировать, он назначает локальный путь к photo свойству photo контроллера. Это отображает фактическое изображение. Позже это значение используется функцией для публикации фотографии.

 $scope.capturePhoto = function(){ CameraService.getPicture().then(function(imageURI) { alert(imageURI); me.photo = imageURI; }, function(err) { alert(err); }); }; 

Далее идет способ размещения фотографии.

 $scope.postPhoto = function(){ ... } 

Внутри мы добавляем параметры для диалога Facebook. Мы снова используем диалог подачи, но на этот раз добавляем другие параметры, такие как name (имя вложения ссылки), caption (текст, который отображается под именем ссылки) и description (отображается под текстом заголовка).

 var dialog_options = { method: "feed", name: me.caption, caption: me.caption, description: me.caption }; 

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

 var photo_data = { 'caption': me.caption }; 

Сделайте HTTP-запрос на загрузку фотографии на сервер. Обратите внимание, что это сервер, используемый приложением для загрузки фотографий и проверки ответов, а не серверы Facebook. Это потому, что мы используем диалог фида Facebook, который не может напрямую принимать загрузки. Все, что он может сделать, это принять URL-адрес изображения и добавить его в качестве ссылки на сообщение. Это означает, что мы просто ссылаемся на изображение. Сервер возвращает имя файла для загруженной фотографии, и мы используем его в качестве значения для атрибута picture в диалоговом окне.

 RequestsService.uploadPhoto(me.photo, photo_data).then(function(response){ var res = JSON.parse(response.response); dialog_options.picture = me.base_uploads_url + res.image_url; ... }, function(response){ alert(JSON.stringify(response)); }); 

Получив это, мы вызываем showDialog чтобы открыть другое диалоговое окно Facebook, которое ссылается на загруженную фотографию

 facebookConnectPlugin.showDialog(dialog_options, function (response) { RequestsService.sendData(response); alert(JSON.stringify(response)) }, function (response) { RequestsService.sendData(response); alert(JSON.stringify(response)) } ); 

Вот как выглядит размещение фотографии:

выкладываю фото

Наконец, для DialogController у нас есть метод sendMessage который открывает диалог отправки Facebook и мы передаем URL-адрес, введенный пользователем. Диалог отправки затем создает предварительный просмотр для этого URL и позволяет пользователю выбрать, кому его отправлять, и необязательное текстовое сообщение.

 $scope.sendMessage = function(){ facebookConnectPlugin.showDialog( { method: "send", link: me.url }, function (response) { RequestsService.sendData(response); alert(JSON.stringify(response)) }, function (response) { RequestsService.sendData(response); alert(JSON.stringify(response)) } ); }; 

Вот как должна выглядеть отправка сообщений:

Отправка сообщения

DialogController используется в этих трех представлениях:
— просмотр статуса публикации
— вид для размещения фотографии
— вид для отправки сообщения

Представление для статуса публикации ( www / templates / post-status.html ) принимает значения для URL-адреса и заголовка статуса для публикации. При нажатии на кнопку « Статус сообщения» открывается диалоговое окно фида Facebook.

 <ion-view title="Post Status" ng-controller="DialogController as dialog_ctrl"> <ion-nav-buttons side="left"> <button menu-toggle="left" class="button button-icon icon ion-navicon"></button> </ion-nav-buttons> <ion-content class="has-header padding"> <div class="list"> <label class="item item-input"> <input type="url" ng-model="dialog_ctrl.url" placeholder="URL"> </label> <label class="item item-input"> <input type="text" ng-model="dialog_ctrl.caption" placeholder="Caption"> </label> </div> <button class="button button-positive button-block" ng-click="postStatus()"> Post Status </button> </ion-content> </ion-view> 

Представление для отправки сообщения ( www / templates / send-message.html ) принимает URL-адрес, которым пользователь хочет поделиться. Нажатие на кнопку « Отправить сообщение» открывает диалоговое окно отправки в Facebook.

 <ion-view title="Send Message" ng-controller="DialogController as dialog_ctrl"> <ion-nav-buttons side="left"> <button menu-toggle="left" class="button button-icon icon ion-navicon"></button> </ion-nav-buttons> <ion-content class="has-header padding"> <div class="list"> <label class="item item-input"> <input type="url" ng-model="dialog_ctrl.url" placeholder="URL"> </label> </div> <button class="button button-balanced button-block" ng-click="sendMessage()"> Send Message </button> </ion-content> </ion-view> 

Представление для публикации фотографий ( www / templates / post-photo.html ) содержит кнопку для захвата фотографий. Как мы видели в DialogController , это открывает приложение камеры по умолчанию на устройстве. После того, как фотография была сделана, она отображается внутри #photo-container div вместе с текстовым полем, которое запрашивает у пользователя подпись. При нажатии на кнопку «Фотография» открывается диалоговое окно канала, в котором отображается предварительный просмотр сообщения.

 <ion-view title="Post Photo" ng-controller="DialogController as dialog_ctrl"> <ion-nav-buttons side="left"> <button menu-toggle="left" class="button button-icon icon ion-navicon"></button> </ion-nav-buttons> <ion-content class="has-header padding"> <button class="button button-balanced button-block" ng-click="capturePhoto()"> Capture Photo </button> <div id="photo-container" ng-if="dialog_ctrl.photo"> <div class="card"> <img ng-src="{{ dialog_ctrl.photo }}"> </div> <div class="list"> <label class="item item-input"> <input type="text" ng-model="dialog_ctrl.caption" placeholder="Caption"> </label> </div> <button class="button button-balanced button-block" ng-click="postPhoto()"> Post Photo </button> </div> </ion-content> </ion-view> 

Добавление серверного компонента

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

Прежде чем мы продолжим работу с кодом, нам нужно установить следующие зависимости:

  • Express : веб-фреймворк для Node.js.
  • body-parser : используется для анализа тела запроса, используется всякий раз, когда мы отправляем данные на сервер. Данные, которые мы отправляем, анализируются этой библиотекой, чтобы мы могли их использовать.
  • multer : Используется для обработки загрузки файлов.

Чтобы установить зависимости, создайте папку с именем server в корневом каталоге приложения. Здесь мы сохраним файлы, используемые сервером. Внутри папки создайте файл package.json и добавьте следующее:

 { "name": "cordova-social", "version": "0.0.1", "dependencies": { "body-parser": "^1.14.1", "express": "^4.13.3", "multer": "^1.1.0" } } 

Сохраните файл и выполните npm installустановку, чтобы установить зависимости.

Создайте файл app-server.js и добавьте следующее:

 var express = require('express'); var app = express(); var multer = require('multer'); var upload = multer({ dest: 'public/uploads/' }); var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(express.static('public')); var server = app.listen(3000, function () { var host = server.address().address; var port = server.address().port; console.log('Example app listening at http://%s:%s', host, port); }); app.get('/', function (req, res) { res.send('Hello World!'); }); app.post('/data', function(req, res){ console.log('received request'); console.log(req.body); res.send('ok'); }); app.post('/upload', upload.single('file'), function(req, res){ console.log('received upload request'); console.log(req.body); console.log(req.file); res.send({'image_url': req.file.filename}); }); 

Здесь мы сначала импортируем все зависимости и устанавливаем их параметры по умолчанию. Поскольку multerмы устанавливаем папку для загрузки в public / uploads . Создайте эту папку и установите необходимые разрешения, например:

 sudo chmod -R 777 public 
 var express = require('express'); var app = express(); var multer = require('multer'); var upload = multer({ dest: 'public/uploads/' }); 

Установите приложение для использования body-parserбиблиотеки.

 var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); 

Установите общую папку как статический каталог для экспресс. Если файл с именем myphoto.png загружен в каталог public / uploads , он доступен по следующему URL-адресу: http://your-server.com/uploads/myphoto.png

 app.use(express.static('public')); 

Присоедините приложение к порту 3000. Это позволяет получить доступ по адресу http: // localhost: 3000 .

 var server = app.listen(3000, function () { var host = server.address().address; var port = server.address().port; console.log('Example app listening at http://%s:%s', host, port); }); 

Определите маршрут для домашней страницы. Мы используем его только для тестирования, чтобы вы могли проверить, работает ли сервер.

 app.get('/', function (req, res) { res.send('Hello World!'); }); 

Определите маршрут для приема данных, представленных из приложения. Маршрут регистрирует, что запрос был получен, и содержимое тела запроса. Затем он возвращает «хорошо» в качестве ответа.

 app.post('/data', function(req, res){ console.log('received request'); console.log(req.body); res.send('ok'); }); 

Наконец, у нас есть маршрут для приема загруженных файлов. При этом используется uploadобъект, предоставленный multerбиблиотекой, для загрузки одного файла. Как только файл загружен, данные req.fileобъекта становятся доступны в объекте, и мы отправляем имя файла обратно в приложение.

 app.post('/upload', upload.single('file'), function(req, res){ console.log('received upload request'); console.log(req.body); console.log(req.file); res.send({'image_url': req.file.filename}); }); 

Развертывание и запуск приложения

Теперь мы готовы скомпилировать приложение и развернуть его на устройстве Android. Прежде чем мы это сделаем, нам нужно запустить сервер узлов и сделать его доступным через Интернет.

 node app-server.js 

Используйте ngrok, чтобы открыть его в Интернете:

 ngrok http 3000 

Это возвращает URL, который вы можете использовать в приложении. Откройте js / services / RequestsService.js и обновите base_url. В js / controllers / DialogController.js обновить base_uploads_url.

Скомпилируйте и запустите приложение для Android:

 cordova build android 

Вывод

Это оно!Из этого урока вы узнали, как работать с API Facebook в приложении Cordova. В частности, вы узнали, как входить и выходить из Facebook, используя Graph API для получения данных о пользователях и диалоги Facebook для публикации статуса и отправки сообщений. Вы можете получить доступ к исходному коду, используемому в этом руководстве, в этом репозитории Github, и я хотел бы услышать любые ваши комментарии или вопросы.