编写实时NativeScript应用程序代码:社交登录和Firebase

NativeScript是用于使用XML,CSS和JavaScript构建跨平台本机移动应用程序的框架。 在本系列中,我们正在尝试使用NativeScript应用程序可以执行的一些很酷的操作:地理位置和Google Maps集成,SQLite数据库,Firebase集成和推送通知。 在此过程中,我们正在构建一个具有实时功能的健身应用程序,它将使用这些功能中的每一个。

在本教程中,您将学习如何将Facebook登录名添加到NativeScript应用程序。 您还将学习如何使用Firebase在Fitness应用程序中存储步行会议数据。

您将要创造的

从上一教程中挑选出来,现在让我们添加社交标签的内容。 默认情况下,显示用于登录Facebook的按钮,如下所示:

未登录

当用户首次登录时,Facebook应用程序会请求访问公共资料和电子邮件地址的权限:

Facebook权限

它还要求朋友列表作为添加的权限。

用户登录后,将显示以下屏幕:

社会标签

在此处显示当前登录用户的信息和步行会话的排行榜。 请注意,仅记录了最新的步行会话。

设置项目

如果您已关注本系列的上一篇文章 ,有关SQLite的信息,则只需使用相同的项目并构建我们将在本教程中添加的功能。 否则,您可以创建一个新项目,并将启动 程序文件复制到项目的应用程序文件夹中。

tns create fitApp --appid "com.yourname.fitApp"

之后,您还需要安装地理位置,Google Maps和SQLite插件:

tns plugin add nativescript-geolocation
tns plugin add nativescript-google-maps-sdk
tns plugin add nativescript-sqlite

安装后,您需要配置Google Maps插件。 您可以通过阅读本早期教程中有关安装Google Maps插件的部分来阅读有关如何执行此操作的完整说明。

之后,您还需要安装fecha (用于格式化日期的库):

npm install --save fecha

完成所有步骤后,您应该准备继续本教程。

运行项目

您可以通过执行tns run android来运行项目。 但是由于该应用程序将使用地理定位功能,因此我建议您使用GPS模拟器来快速设置和更改位置。 您可以在之前的教程中的“ 运行应用程序 ”部分中了解有关操作方法的信息。

设置Firebase应用

使用Firebase时,您要做的第一件事是创建Firebase应用程序。 您可以通过转到console.firebase.com并单击Add project来实现 。 输入项目名称,并单击C reate项目按钮。 确保项目名称与应用程序名称相同。 在这种情况下,应用程序ID为com.yourname.fitApp因此应用程序的名称为fitApp

创建Firebase项目

创建应用程序后,您将被重定向到应用程序的仪表板页面。 在此处,您可以单击将Firebase添加到您的Android应用程序 ,输入应用程序ID,然后单击注册应用程序按钮。

将Firebase添加到Android应用

接下来,下载google-services.json文件并将其复制到app / App_Resources / android目录。 该文件包含应用程序与Firebase通信所需的所有设置。

Firebase仪表板中所述的下一步是包括Firebase SDK。 但这已在插件中完成,因此我们不再需要这样做。

设置Facebook应用

由于我们将使用Facebook登录,因此我们还需要创建一个Facebook应用。 转到developers.facebook.com并创建一个新的Facebook应用程序:

创建Facebook应用

创建应用程序后,您将被重定向到应用程序仪表板。 在此处,点击+添加产品菜单,然后选择Facebook登录

在“ 客户端 OAuth设置”下 ,启用“ 强制Web OAuth重新认证从设备登录”以外的所有功能。 对于有效的OAuth重定向URI ,您可以通过返回Firebase仪表板,单击Authentication ,然后将Facebook作为身份验证方法来实现:

认证方式

在启用它之前,您必须输入Facebook应用程序ID和应用程序密钥。 您可以从您先前创建的Facebook应用程序的仪表板上获取该信息。

完成后,单击“ 保存”,然后将OAuth重定向URI复制到Facebook应用程序设置中。 不要忘记保存更改。

接下来,您还需要将Android添加为平台。 您可以转到“ 基本设置”,然后单击“ 添加平台”

Android设置

com.yourname.fitApp设置为Google Play包名称的值,并将com.tns.NativeScriptActivity设置为类名称。

请注意,如果以后要将该应用发布到应用商店,则需要为该应用的.apk文件生成一个哈希,并将其添加到关键哈希字段下。 还要注意,为了进行测试,您将只能使用创建应用程序时使用的Facebook开发人员帐户。 如果要添加其他Facebook帐户进行测试,则可以在oles下添加它们。

安装Firebase插件

为了集成Firebase,我们需要为NativeScript安装Firebase插件 。 这使在Firebase中实现Facebook登录和实时数据库功能更加容易:

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>标签:

<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文件并添加以下内容:

<?xml version='1.0' encoding='utf-8'?>
<resources>
     <string name="facebook_app_id">YOUR_FACEBOOK_APP_ID</string>
</resources>

请确保将YOUR_FACEBOOK_APP_ID替换为您先前创建的Facebook应用的应用ID。

解决构建错误

如果在安装插件后遇到构建错误,请确保检查存储库自述文件中的“ Android上已知问题”部分。 如果您的特定问题不存在,请尝试浏览问题页面

对于我来说,我遇到的主要问题是Google Maps插件的兼容性问题。 由于该插件也使用Google Play服务,因此所使用的不同版本存在冲突。 为了解决这个问题,我必须打开app / App_Resources / Android / app.gradle文件并指定要使用的Google Play服务版本:

android {  
  //default config here

  project.ext {
    googlePlayServicesVersion = "11.0.+"
  }
}

在撰写本教程时,它是11.0。 但是请确保通过Android SDK检查当前为您安装的版本。

完成后,您必须卸载android平台( tns platform remove android ),然后尝试再次运行该应用程序( tns run android )。

如果那对您不起作用,并且您仍然遇到相同的构建错误,则可能需要通过创建一个新项目来重新开始。 但是这一次,请尝试在Google Maps插件之前安装Firebase插件。 然后在尝试运行该应用程序之前进行必要的配置更改。

添加代码

现在我们准备添加代码。 我们将首先添加XML,然后添加JavaScript,最后添加CSS代码。

添加UI标记

我们将主要在社交标签视图中工作。 首先,添加用于显示当前登录用户信息的标记以及用于注销的按钮:

<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以显示用户名,距离以及用户的朋友和用户所执行的步骤。

<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登录的按钮:

<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库的代码下面添加以下代码:

var fecha = require('fecha');

var firebase = require("nativescript-plugin-firebase");
var http = require("http");
var applicationSettings = require("application-settings");

我们正在使用nativescript-plugin-firebase与Firebase进行通信,使用http向Facebook的Graph API发出HTTP请求,并使用application-settings来保留用户的登录数据。

初始化Firebase

接下来,使用init()函数初始化Firebase。 这接受一个对象,该对象包含Firebase支持的不同功能的选项(例如,身份验证,实时数据库,云消息传递)。

在下面,我们添加了persist选项,该选项使Firebase可以在本地保存数据,因此离线时仍可以使用该应用程序。 稍后,我们将在身份验证状态更改时(用户登录或注销应用程序时)添加侦听器。

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功能,该功能接受一个包含typefacebookOptions的对象。

type是用于登录的身份验证方法。在这种情况下,它是Facebook。 facebookOptions是一个包含名为scope的数组的对象。 该数组的元素是权限所需的应用从用户请求。

用户登录并同意所有请求的权限后,promise将解析并执行传递给then()的第一个函数。 Facebook用户详细信息作为该函数的参数传递,但是我们唯一需要的就是访问令牌。 我们稍后可以使用它向Facebook的Graph API发出请求,以获取更多信息。

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上更新用户的最新步行会话时,我们将需要访问此数据。

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
        }
    }
);

创建一个新用户

现在,让我们添加用于为新用户保存数据的代码。 首先创建包含用户数据的对象。 然后向Facebook的Graph API发出请求,以获取用户的Facebook ID(仅对此特定应用有效)。

稍后,我们将使用该ID来检查特定的Firebase用户是否是当前用户的朋友。 登录时,Firebase不会返回此ID,这就是为什么我们需要单独发出请求。

返回响应后,我们将使用Firebase的push()方法将用户的数据保存在/users路径中。 这将返回用作此特定用户ID的密钥。 我们稍后将使用它来更新用户的上一次步行会话。 这就是为什么我们还需要将其与用户数据和Facebook访问令牌一起保存在本地。

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; // facebook user ID for this specific app
        
        // create new user
        firebase.push(
          '/users',
          user_data
        ).then(
          function (result) {
            
            var user = {};
            user[result.key] = user_data; // the key is the property containing the user's 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() ,具有五秒钟的延迟,因为登录后需要几秒钟才能使用户数据(Firebase用户密钥,Firebase用户和Facebook Access令牌)可用。

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);

    } 
    
}

接下来,我们添加获取用户朋友的代码。 graph API返回每个用户朋友的ID和名称,但是我们只需要ID。 我们还需要为当前用户推送ID,因为我们也将其显示在页首横幅中。

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); // also push the ID for the current user

        // next: add code for listening for changes in the database

}, function(e){
    console.log('err: ', e);
});

显示排行榜

接下来,添加用于侦听数据库中的更改的代码。 到目前为止,我们尚未真正实现此应用程序的“实时”部分。 这是我们最终添加它的时间。

为此,我们使用addValueEventListener()方法。 当更改指定为第二个参数的路径时,这将接受要执行的功能。 整个值( result )作为参数传递给此函数。

确实没有功能可以指定查询以仅按特定ID过滤结果。 因此,使用朋友ID数组( friends_ids ),我们遍历result并检查当前行是当前用户还是他们的朋友之一。 只有这样,我们才为当前行推送值。 从那里,我们只对数据进行排序和格式化以在UI中显示。

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");

更新最新的步行会议

当用户停止跟踪其当前位置时,我们会在Firebase上更新用户的distancesteps长:

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
);

注销用户

接下来,添加用于注销用户的代码。 这会将UI重置为用户未登录的状态,并且还会清除本地数据。

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文件,并在现有代码下方添加以下内容:

.btn-facebook {
    background-color: #365899;
	color: #fff;
}

.btn-logout {
	background-color: red;
	color: #fff;
}

.profile {
	text-align: center;
}

结论

而已! 在本教程中,您学习了如何将Facebook登录名和Firebase集成到NativeScript应用程序中。 正如您在NativeScript Firebase插件的文档中可能已经注意到的那样,实际上您可以使用该插件做更多的事情。 实际上,我们将使用其云消息传递功能来实现此应用程序的最后一个功能:推送通知。 因此,请继续关注!

翻译自: https://code.tutsplus.com/tutorials/code-a-real-time-nativescript-app-social-login-and-firebase--cms-29413

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值