NativeScript — это платформа для создания кроссплатформенных собственных мобильных приложений с использованием XML, CSS и JavaScript. В этой серии мы попробуем некоторые интересные вещи, которые вы можете сделать с помощью приложения NativeScript: геолокация и интеграция с Google Maps, база данных SQLite, интеграция с Firebase и push-уведомления. Попутно мы создаем фитнес-приложение с возможностями реального времени, которое будет использовать каждую из этих функций.
Из этого руководства вы узнаете, как добавить логин Facebook в свое приложение NativeScript. Вы также узнаете, как использовать Firebase для хранения данных о прогулках в фитнес-приложении.
Что вы будете создавать
Продолжая предыдущий урок, давайте теперь добавим контент для социальной вкладки. По умолчанию кнопка для входа в Facebook отображается так:
Когда пользователь входит в систему в первый раз, приложение Facebook запрашивает разрешение на доступ к общему профилю и адресу электронной почты:
Он также запрашивает список друзей в качестве дополнительного разрешения.
После входа пользователя в систему отображается следующий экран:
Здесь отображается информация для текущего пользователя, вошедшего в систему, и таблица лидеров для сеансов ходьбы. Обратите внимание, что записывается только последний сеанс ходьбы.
Настройка проекта
Если вы следовали предыдущему посту в этой серии статей о SQLite, вы можете просто использовать тот же проект и создать функции, которые мы добавим в этом руководстве. В противном случае вы можете создать новый проект и скопировать начальные файлы в папку приложения вашего проекта.
1
|
tns create fitApp —appid «com.yourname.fitApp»
|
После этого вам также необходимо установить плагины геолокации, Google Maps и SQLite:
1
2
3
|
tns plugin add nativescript-geolocation
tns plugin add nativescript-google-maps-sdk
tns plugin add nativescript-sqlite
|
После установки вам необходимо настроить плагин Google Maps. Вы можете прочитать подробные инструкции о том, как это сделать, прочитав раздел Установка плагина Google Maps в этом предыдущем руководстве .
После этого вам также необходимо установить fecha , библиотеку для форматирования дат:
1
|
npm install —save fecha
|
Как только все это будет сделано, вы должны быть готовы следовать этому уроку.
Запуск проекта
Вы можете запустить проект, выполнив tns run android
. Но так как это приложение будет использовать функцию геолокации, я рекомендую вам использовать эмулятор GPS для быстрой настройки и изменения вашего местоположения. О том, как это сделать, вы можете прочитать в разделе « Запуск приложения» в предыдущем руководстве .
Настройка приложения Firebase
Первое, что вам нужно сделать при работе с Firebase, это создать приложение Firebase. Вы можете сделать это, перейдя на console.firebase.com и нажав Добавить проект . Введите название проекта и нажмите кнопку « Создать проект» . Убедитесь, что имя проекта совпадает с именем приложения. В этом случае идентификатор приложения — com.yourname.fitApp
поэтому имя приложения — fitApp
.
Как только приложение будет создано, вы будете перенаправлены на страницу его панели. Оттуда вы можете нажать Добавить Firebase в ваше приложение для Android , ввести идентификатор приложения и нажать кнопку « Зарегистрировать приложение» .
Затем загрузите файл google-services.json и скопируйте его в каталог app / App_Resources / android . Этот файл содержит все параметры, необходимые приложению для взаимодействия с Firebase.
Следующим шагом, указанным на панели инструментов Firebase, является включение Firebase SDK. Но это уже сделано в плагине, поэтому нам больше не нужно это делать.
Настройка приложения Facebook
Поскольку мы собираемся использовать логин на Facebook, нам также нужно создать приложение для Facebook. Перейдите на developers.facebook.com и создайте новое приложение Facebook:
Как только приложение будет создано, вы будете перенаправлены на панель инструментов приложения. Оттуда, нажмите на + Добавить продукт меню и выберите Facebook Войти .
В разделе Параметры OAuth- клиента включите все, кроме принудительной повторной проверки подлинности OAuth и входа в систему с устройств . Для действительных URI перенаправления OAuth вы можете получить это, вернувшись на панель инструментов Firebase, щелкнув по аутентификации и включив Facebook в качестве метода аутентификации:
Прежде чем вы сможете включить его, вы должны ввести идентификатор приложения Facebook и секретный ключ приложения. Вы можете получить это из панели инструментов приложения Facebook, которое вы создали ранее.
После этого нажмите « Сохранить» и скопируйте URI перенаправления OAuth в настройки приложения Facebook. Не забудьте сохранить изменения.
Далее вам также необходимо добавить Android в качестве платформы. Вы можете сделать это, перейдя в Основные настройки и нажав Добавить платформу :
Установите com.yourname.fitApp в качестве значения для имени пакета Google Play и com.tns.NativeScriptActivity для имени класса.
Обратите внимание, что если вы собираетесь позже выпустить приложение в магазин приложений, вам необходимо сгенерировать хеш для файла .apk приложения и добавить его в поле ключевых хешей . Также обратите внимание, что для тестирования вы сможете использовать только учетную запись разработчика Facebook, которую вы использовали для создания приложения. Если вы хотите добавить другие учетные записи Facebook для тестирования, вы можете добавить их в разделе oles .
Установка плагина Firebase
Чтобы интегрировать Firebase, нам нужно установить плагин Firebase для NativeScript . Это облегчает реализацию входа в Facebook и функцию базы данных в реальном времени в Firebase:
1
|
tns plugin add nativescript-plugin-firebase
|
После завершения установки установщик задаст вам несколько вопросов, касающихся функций Firebase, которые вы будете использовать в приложении. Ответьте да для входа в Facebook и нет для остальных.
Настройка интеграции с Facebook
Вы должны сообщить приложению, с каким приложением Facebook оно будет общаться. Вы можете сделать это, открыв файл app \ App_Resources \ Android \ AndroidManifest.xml и добавив <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
под <application>
:
01
02
03
04
05
06
07
08
09
10
11
12
|
<application
android:name=»com.tns.NativeScriptApplication»
android:allowBackup=»true»
android:icon=»@drawable/icon»
android:label=»@string/app_name»
android:theme=»@style/AppTheme»>
<!— add this: —>
<meta-data android:name=»com.facebook.sdk.ApplicationId» android:value=»@string/facebook_app_id»/>
<!— other stuff —>
</application>
|
Затем создайте файл app \ App_Resources \ Android \ values \ facebooklogin.xml и добавьте следующее:
1
2
3
4
|
<?xml version=’1.0′ encoding=’utf-8′?>
<resources>
<string name=»facebook_app_id»>YOUR_FACEBOOK_APP_ID</string>
</resources>
|
Обязательно замените YOUR_FACEBOOK_APP_ID
идентификатором приложения Facebook, которое вы создали ранее.
Устранение ошибок сборки
Если вы получаете ошибки сборки после установки плагина, обязательно ознакомьтесь с разделом Известные проблемы в Android в README репозитория. Если вашей конкретной проблемы нет, попробуйте пролистать страницу с проблемами .
Что касается меня, то основной проблемой, с которой я столкнулся, была проблема совместимости с плагином Google Maps . Поскольку этот плагин также использует Сервисы Google Play, возник конфликт с использованием разных версий. Чтобы решить эту проблему, мне пришлось открыть файл app / App_Resources / Android / app.gradle и указать версию Google Play Services:
1
2
3
4
5
6
7
|
android {
//default config here
project.ext {
googlePlayServicesVersion = «11.0.+»
}
}
|
На момент написания этого урока он был на 11.0. Но не забудьте проверить, какая версия установлена для вас через Android SDK.
Как только это будет сделано, вы должны удалить платформу Android ( tns platform remove android
) и попытаться снова запустить приложение ( tns run android
).
Если это не работает для вас, и вы по-прежнему получаете ту же ошибку сборки, возможно, вам придется начать все сначала, создав новый проект. Но на этот раз попробуйте установить плагин Firebase перед плагином Google Maps. Затем выполните необходимые изменения конфигурации, прежде чем пытаться запустить приложение.
Добавление кода
Теперь мы готовы добавить код. Сначала мы добавим XML, затем JavaScript и, наконец, код CSS.
Добавление разметки интерфейса
Мы будем работать в основном в представлении социальных вкладок. Сначала добавьте разметку для отображения информации о текущем вошедшем в систему пользователе, а также кнопку выхода из системы:
1
2
3
4
5
6
|
<StackLayout width=»140″ class=»profile p-20″ visibility=»{{ is_loggedin ? ‘visible’ : ‘collapsed’ }}»>
<Image src=»{{ profile_photo }}» stretch=»aspectFit» />
<Label text=»{{ user_name }}» textWrap=»true» />
<Button text=»Logout» tap=»{{ logout }}»
class=»btn-logout» />
</StackLayout>
|
Ниже приведена разметка для отображения таблицы лидеров. Это перебирает данные friends_data
для отображения имени пользователя, расстояния и шагов, сделанных друзьями пользователя и пользователем.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
<StackLayout visibility=»{{ is_loggedin && friends_data ? ‘visible’ : ‘collapsed’ }}»>
<Label text=»Leaderboard» class=»heading» textWrap=»true» />
<GridLayout columns=»2*,*,*» rows=»auto» class=»item item-header»>
<Label text=»Name» textWrap=»true» row=»0″ col=»0″/>
<Label text=»Distance» textWrap=»true» row=»0″ col=»1″ />
<Label text=»Steps» textWrap=»true» row=»0″ col=»2″ />
</GridLayout>
<ListView items=»{{ friends_data }}»>
<ListView.itemTemplate>
<GridLayout columns=»2*,*,*» rows=»auto» class=»item item-row»>
<Label text=»{{ user_name }}» textWrap=»true» row=»0″ col=»0″/>
<Label text=»{{ distance }}» textWrap=»true» row=»0″ col=»1″ />
<Label text=»{{ steps }}» textWrap=»true» row=»0″ col=»2″ />
</GridLayout>
</ListView.itemTemplate>
</ListView>
</StackLayout>
|
Если в данный момент ни один пользователь не вошел в систему, мы показываем кнопку для входа через Facebook:
1
2
3
4
5
|
<StackLayout class=»p-20″>
<Button text=»Login with Facebook» tap=»{{ loginFacebook }}»
class=»btn-facebook»
visibility=»{{ is_loggedin ? ‘collapsed’ : ‘visible’ }}» />
</StackLayout>
|
Импорт библиотек
Откройте файл main-view-model.js и добавьте следующий код для импорта библиотеки fecha:
1
2
3
4
5
|
var fecha = require(‘fecha’);
var firebase = require(«nativescript-plugin-firebase»);
var http = require(«http»);
var applicationSettings = require(«application-settings»);
|
Мы используем nativescript-plugin-firebase
для общения с Firebase, http
для выполнения HTTP-запросов к API Graph Facebook и application-settings
для сохранения данных для входа пользователя.
Инициализация Firebase
Затем инициализируйте Firebase с помощью функции init()
. Это принимает объект, который содержит параметры для различных функций, поддерживаемых Firebase (например, аутентификация, база данных в реальном времени, облачные сообщения).
Ниже мы добавляем опцию persist
, которая позволяет Firebase сохранять данные локально, чтобы приложение можно было использовать в автономном режиме. Позже мы добавим прослушиватель, когда меняется статус аутентификации (когда пользователь входит в систему или выходит из приложения).
01
02
03
04
05
06
07
08
09
10
11
|
firebase.init({
persist: true,
// add later: code for listening when auth status changes
}).then(
function(instance){
console.log(«firebase.init done»);
},
function(error){
console.log(«firebase.init error: » + error);
}
);
|
Вход пользователя в
Затем добавьте код, который будет выполняться, когда пользователь нажимает на кнопку для входа в Facebook. При этом используется функция login
в login
, которая принимает объект, содержащий type
и facebookOptions
.
type
— это метод аутентификации, который будет использоваться для входа в систему. В данном случае это Facebook. facebookOptions
— это объект, содержащий массив с именем scope
. Элементами этого массива являются разрешения, которые вы хотите, чтобы приложение запрашивало у пользователя.
Как только пользователь вошел в систему и согласился со всеми запрашиваемыми разрешениями, обещание разрешает и выполняет первую функцию, переданную then()
. Данные пользователя Facebook передаются в качестве аргумента этой функции, но единственное, что нам нужно, это токен доступа. Мы можем использовать это позже, чтобы отправлять запросы в API Graph Facebook для получения дополнительной информации.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
viewModel.loginFacebook = function() {
firebase.login({
type: firebase.LoginType.FACEBOOK,
facebookOptions: {
scope: [‘public_profile’, ’email’, ‘user_friends’]
}
}).then(
function(fb_result){
var fb_access_token = fb_result.providers[1].token;
// next: add code for checking if user is new or not
},
function (err) {
console.log(‘error logging in to facebook: ‘, err);
}
);
}
|
Далее мы отправим запрос в базу данных Firebase, чтобы проверить, существует ли пользователь уже или нет. Для этого мы используем метод query()
. Это принимает функцию для выполнения, когда ответ возвращается в качестве первого аргумента. Второй аргумент — это путь, по которому выполняется запрос, а третий — сам запрос.
Если пользователь уже существует, query()
вернет данные пользователя. Затем мы сохраняем данные локально, используя настройки приложения . Нам понадобится получить доступ к этим данным позже, когда мы будем слушать изменения статуса авторизации и когда мы обновим последний сеанс ходьбы пользователя в Firebase.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
firebase.query(
function(firebase_result){
if(!firebase_result.error){
if(firebase_result.value == null){ //user doesn’t exist yet
//next: add code for saving the data for new user
}else{
// user already exists
for(var user_key in firebase_result.value){
// save user’s data locally
applicationSettings.setString(‘user_key’, user_key);
applicationSettings.setString(‘user’, JSON.stringify(firebase_result.value));
applicationSettings.setString(‘fb_token’, fb_access_token);
}
}
}
},
‘/users’,
{
singleEvent: true, // for checking if the value exists (return the whole data)
orderBy: { // the property in each of the objects in which to perform the query
type: firebase.QueryOrderByType.CHILD,
value: ‘uid’
},
range: { // the comparison operator
type: firebase.QueryRangeType.EQUAL_TO,
value: fb_result.uid
},
limit: { // limit to only return the first result
type: firebase.QueryLimitType.FIRST,
value: 1
}
}
);
|
Создать нового пользователя
Теперь давайте добавим код для сохранения данных для нового пользователя. Начните с создания объекта, который содержит пользовательские данные. Затем сделайте запрос к API Graph Facebook, чтобы получить идентификатор Facebook пользователя (который действителен только для этого конкретного приложения).
Позже мы будем использовать этот идентификатор, чтобы проверить, является ли конкретный пользователь Firebase другом текущего пользователя. Firebase не возвращает этот идентификатор при входе в систему, поэтому нам нужно сделать отдельный запрос.
Как только ответ будет возвращен, мы будем использовать метод push()
Firebase, чтобы сохранить данные /users
пути /users
. Это возвращает ключ, который служит идентификатором для этого конкретного пользователя. Мы собираемся использовать его позже, чтобы обновить последнюю сессию пользователя. Вот почему нам также необходимо сохранить его локально вместе с данными пользователя и токеном доступа Facebook.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
var user_data = {
‘uid’: fb_result.uid,
‘user_name’: fb_result.name,
‘profile_photo’: fb_result.profileImageURL
};
http.getJSON(‘https://graph.facebook.com/me?access_token=’ + fb_access_token)
.then(function(r){
user_data.id = r.id;
// create new user
firebase.push(
‘/users’,
user_data
).then(
function (result) {
var user = {};
user[result.key] = user_data;
// store user’s data locally
applicationSettings.setString(‘user_key’, result.key);
applicationSettings.setString(‘user’, JSON.stringify(user));
applicationSettings.setString(‘fb_token’, fb_access_token);
}
);
});
|
Теперь, когда мы добавили код для входа пользователя в систему, следующим шагом будет onAuthStateChanged
firebase.init()
и добавление onAuthStateChanged
. Эта функция будет выполняться каждый раз, когда изменяется статус авторизации (когда пользователь входит в систему или выходит из нее). Если пользователь вошел в систему, мы хотим обновить пользовательский интерфейс, чтобы показать текущего пользователя.
Обратите внимание, что мы оборачиваем его внутри setTimeout()
с setTimeout()
задержкой, поскольку после входа в систему для доступа к данным пользователя (ключ пользователя Firebase, пользователь Firebase и маркер доступа Facebook) требуется несколько секунд.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
persist: true,
onAuthStateChanged: function (data) {
if(data.loggedIn){ // is a user logged in?
setTimeout(function(){
// update UI to show the current user
viewModel.set(‘is_loggedin’, true);
viewModel.set(‘profile_photo’, data.user.profileImageURL);
viewModel.set(‘user_name’, data.user.name);
// next: add code for getting friends list
}, 5000);
}
}
|
Далее добавляем код для получения друзей пользователя. API Graph возвращает идентификатор и имя каждого из друзей пользователя, но нам нужны только идентификаторы. Нам также нужно нажать на идентификатор текущего пользователя, так как мы собираемся отобразить его и в списке лидеров.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
var user_key = applicationSettings.getString(‘user_key’);
var user = JSON.parse(applicationSettings.getString(‘user’));
var fb_token = applicationSettings.getString(‘fb_token’);
http.getJSON(‘https://graph.facebook.com/me/friends?access_token=’ + fb_token)
.then(function (r) {
// extract the ID’s
var friends_ids = r.data.map(function(obj){
return obj.id;
});
friends_ids.push(user[user_key].id);
// next: add code for listening for changes in the database
}, function(e){
console.log(‘err: ‘, e);
});
|
Отображение таблицы лидеров
Затем добавьте код для прослушивания изменений в базе данных. До сих пор мы не реализовали часть этого приложения в режиме реального времени. Это время, когда мы наконец добавим это.
Для этого мы используем метод addValueEventListener()
. Это принимает функцию, которую вы хотите выполнить, когда вносится изменение в путь, указанный вами в качестве второго аргумента. Все значение ( result
) передается в качестве аргумента этой функции.
Там действительно нет функциональности, чтобы указать запрос, чтобы фильтровать результат только по определенным идентификаторам. Таким образом, используя массив идентификаторов друзей ( friends_ids
), мы перебираем result
и проверяем, является ли текущий ряд текущим пользователем или одним из его друзей. Только тогда мы нажимаем значение для текущей строки. Оттуда мы просто сортируем и форматируем данные для отображения в пользовательском интерфейсе.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
firebase.addValueEventListener(function(result){
var friends_data = [];
for(var row in result.value){
var friend = result.value[row];
// check if the current row is the current user or one of their friends
if(friends_ids.indexOf(friend.id) !== -1){
friends_data.push(result.value[row]);
}
}
// sort data in descending order of the steps
var sorted_friends_data = friends_data.sort(function(a, b) {
return b.steps — a.steps;
});
// format the data for displaying
var formatted_sorted_friends_data = sorted_friends_data.map(function(obj, key){
var updated_obj = obj;
updated_obj.distance = commafy(obj.distance) + ‘m’;
updated_obj.steps = commafy(obj.steps);
return updated_obj;
});
// update the UI
viewModel.set(‘friends_data’, formatted_sorted_friends_data);
}, «/users»);
|
Обновление последней пешеходной сессии
Когда пользователь перестает отслеживать свое текущее местоположение, мы обновляем distance
и steps
пользователя в Firebase:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
viewModel.set(‘walks’, walks);
if(walks.length > 0){
viewModel.set(‘has_walks’, true);
}
var user_key = applicationSettings.getString(‘user_key’);
var user = applicationSettings.getString(‘user’);
var user_data = JSON.parse(user);
user_data[user_key].distance = total_distance;
user_data[user_key].steps = total_steps;
// update user’s data
firebase.update(
‘/users’,
user_data
);
|
Выход пользователя
Затем добавьте код для выхода пользователя из системы. Это сбрасывает пользовательский интерфейс в состояние, когда пользователь не вошел в систему, а также очищает локальные данные.
1
2
3
4
5
6
7
8
9
|
viewModel.logout = function() {
firebase.logout();
viewModel.set(‘is_loggedin’, false);
viewModel.set(‘profile_photo’, null);
viewModel.set(‘user_name’, null);
applicationSettings.clear();
}
|
Добавление стилей
Наконец, откройте файл app / app.css и добавьте следующее ниже существующего кода:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
.btn-facebook {
background-color: #365899;
color: #fff;
}
.btn-logout {
background-color: red;
color: #fff;
}
.profile {
text-align: center;
}
|
Вывод
Это оно! Из этого урока вы узнали, как интегрировать логин Facebook и Firebase в приложение NativeScript. Как вы могли заметить в документации к плагину NativeScript Firebase, вы действительно можете сделать намного больше с этим плагином. Фактически, мы будем использовать функцию Cloud Messaging для реализации последней функции для этого приложения: Push-уведомления. Так что следите за обновлениями!
А пока посмотрите другие наши посты о NativeScript и кроссплатформенных мобильных приложениях!