• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

使用NativeScript编写实时应用程序:推送通知

nativescript致力于使用 XML、 cssjavascript构建跨平台的原生移动应用程序。在本系列中,我们将尝试使用 NativeScript 应用程序可以做的一些很酷的事情:地理定位和 Google 地图集成、sqlite 数据库firebase 集成和推送通知。在此过程中,我们正在构建一个具有实时功能的健身应用程序,该应用程序将使用这些功能中的每一个。

在本教程中,您将了解使用 Firebase 云消息传递服务向 NativeScript 应用添加推送通知是多么容易。

你将要创造什么

从上一个教程开始,您将向应用程序添加推送通知。当用户打破他们当前的记录或当他们的一个朋友离开他们时,将触发通知。

设置项目

如果您已按照之前的 Firebase 教程进行操作,则可以简单地使用相同的项目并构建我们将在本教程中添加的功能。否则,您可以创建一个新项目并将启动文件复制到项目的 app 文件夹中。

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

之后,您还需要安装 geolocation、Google Maps、sqlite 和 Firebase 插件:

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

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

接下来,安装用于格式化日期的 fecha 库:

npm install --save fecha

之后,您还需要配置 Firebase 插件。请务必阅读上一教程中的以下部分,以便让应用程序运行:

  • 运行项目

  • 设置 Firebase 应用

  • 设置 Facebook 应用程序

  • 安装 Firebase 插件

  • 配置 Facebook 集成

由于我们已经在上一篇文章中设置了 Firebase 插件,因此只需要做一些工作来设置推送通知。

首先,您必须通过进入节点_modules/nativescript-plugin-firebase 目录并运行npm run config这一次,同时选择 Facebook 身份验证和消息传递。

完成后,打开项目根目录中的firebase.nativescript.json 文件,并确保将messaging 其设置为true

{
    "using_ios": false,
    "using_android": true,
    "remote_config": false,
    "messaging": true,
    "crash_reporting": false,
    "storage": false,
    "facebook_auth": true,
    "google_auth": false,
    "admob": false,
    "invites": false
}

接下来,打开 app/App_Resources/Android/AndroidManifest.xml 并在<application>这将为应用启用 Firebase 消息服务:

<application ...>

<service android:name="org.nativescript.plugins.firebase.MyFirebaseInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_event"/>
    </intent-filter>
</service>
<service android:name="org.nativescript.plugins.firebase.MyFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

</application>

运行项目

您可以通过执行来运行项目tns run android但是由于这个应用程序将建立在地理定位功能上,我建议您使用 GPS 模拟器来快速设置和更改您的位置。您可以在前面教程的运行应用程序部分了解如何执行此操作

如果您遇到任何构建错误,您可以删除平台并重新运行应用程序:

tns platform remove android
tns run android

设置 Firebase 云功能

您将使用Firebase Cloud Functions 创建一个发送推送通知的服务器此 Firebase 功能用于在您正在使用的 Firebase 功能中发生特定事件时运行后端代码 - 例如,如果实时数据库中保存了新数据,或者通过Firebase 身份验证服务。对于此应用程序,您将使用 HTTP 触发器 在移动应用程序向特定端点发出请求时发送推送通知。

要使用 Firebase Cloud Functions,您首先需要firebase-tools 全局安装该软件包:

npm install -g firebase-tools

接下来,创建一个新文件夹来存放服务器代码。这应该在您的应用程序文件夹之外。在该文件夹中,安装firebase-functions 软件包:

npm install firebase-functions@latest --save

安装完成后,运行firebase login这将打开一个新的浏览器选项卡,允许您使用 Google 帐户登录。完成整个过程并同意要求的所有权限。

登录后,您现在可以为特定 Firebase 项目初始化 Firebase 函数:

firebase init functions

这将询问您是否要设置默认项目。选择您在上一教程中创建的 Firebase 项目:

使用NativeScript编写实时应用程序:推送通知  第1张

接下来,将询问您是否要安装依赖项。说是。

安装完所有依赖项后,您应该会在目录中看到一个firebase.json 文件和一个functions 文件夹。您将要处理的文件是functions/index.js 文件。打开该文件,您将看到以下内容:

const functions = require('firebase-functions');

// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
//  response.send("Hello from Firebase!");
// });

取消注释该helloWorld 函数,您将看到 HTTP 触发器的运行情况。

exports.helloWorld = functions.https.onRequest((request, response) => {
    response.send("Hello from Firebase!");
});

运行以下命令将函数部署到云端:

firebase deploy --only functions

部署完成后,它应该会显示已部署函数的 URL:

使用NativeScript编写实时应用程序:推送通知  第2张

从浏览器访问该 URL 以查看输出“Hello from Firebase!”

添加服务器代码

现在您已准备好添加用于实现推送通知的代码。首先,您将添加服务器组件的代码,然后是应用程序的代码。

打开functions/index.js 文件并清空其内容。 

创建 Firebase 函数

导入您需要的 Firebase 软件包:

const functions = require('firebase-functions'); // for listening to http triggers
const admin = require('firebase-admin'); // for accessing the realtime database
admin.initializeApp(functions.config().firebase); // initialize the Firebase Admin SDK

创建init_push 函数。请注意,任何请求方法都会调用 HTTP 触发器,因此您必须筛选要处理的请求方法。在这种情况下,我们只想处理post 请求。我们希望应用程序提交idsteps和 friend_ids 作为请求数据。 

exports.init_push = functions.https.onRequest((request, response) => {
    
    if(request.method == 'POST'){

        var id = request.body.id; // ID of the user who made the request (Firebase Auth ID)
        var steps = parseInt(request.body.steps); // latest steps, not recorded yet
        var friend_ids = request.body.friend_ids.split(','); 

        friend_ids.push(id); // also include the ID of the current user

        // next: add code for getting the user and friends data
    }

});

获取用户和好友数据

接下来,查询 Firebase 数据库以检查用户 ID 是否存在。这是保护端点的一种方式,因此不仅仅是任何人都可以触发推送通知。(当然,真正的应用程序应该有更好的后端安全性,这样用户就无法欺骗自己的数据或其他人的数据。) 

如果用户确实存在,则再次查询数据库以返回所有用户。请注意,Firebase 目前不提供基于 ID 数组返回记录的方法,因此我们必须自己过滤相关数据:

admin.database().ref('/users')
    .orderByChild('id')
    .limitToFirst(1)
    .equalTo(id)
    .once('value').then(snapshot => {
    
    var user_data = snapshot.val();

    if(user_data){
        // get all users from the database
        admin.database().ref('/users')
            .once('value').then(snapshot => {
            // next: add code for getting the current user's data and their friends data
        });
    }
});

接下来,遍历从 Firebase 返回的结果并创建一个包含friends_data完成后,根据每个用户的步数对数组进行排序。步数最多的具有第一个索引。

var friends_data = [];
var current_user_data = null;
var notification_data = {};
var has_notification = false;

var users = snapshot.val();
for(var key in users){
    var user_id = users[key].id;
    
    if(friend_ids.indexOf(user_id) != -1 && id != user_id){ // the current user's friends
        friends_data.push(users[key]);
    }else if(id == user_id){ // the current user
        current_user_data = users[key];
    }
}

// sort in descending order by the number of steps
var sorted_friends_data = friends_data.sort(function(a, b) {
    return b.steps - a.steps;
}); 

// next: add code for constructing the notification payload

构造通知负载

现在我们已准备好确定谁将接收通知并构建通知有效负载。谁是第一名?是当前用户还是用户的朋友之一?由于当前用户在打破第一名的整体记录时也会打破自己的记录,因此我们只需要检查该记录是否已被打破。

if(steps > sorted_friends_data[0].steps){
    // notify friend who was overtaken
    var diff_steps = steps - sorted_friends_data[0].steps;
    notification_data = {
        payload: {
            title: 'One of your friends beat your record',
            body: 'Too bad, your friend ' + current_user_data.user_name + ' just overtook you by ' + diff_steps + ' steps'
        },
        device_token: sorted_friends_data[0].device_token
    };
    has_notification = true;
    
}else if(steps > current_user_data.steps){
    // notify current user
    var diff_steps = steps - current_user_data.steps;
    notification_data = {
        payload: {
            title: 'You beat your record!',
            body: 'Congrats! You beat your current record by ' + diff_steps + ' steps!' 
        },
        device_token: current_user_data.device_token
    };
    has_notification = true;
}

// next: add code for sending push notification

发送通知

最后,发出通知:

if(has_notification){
    
    var payload = {
      notification: notification_data.payload
    };
    
    // send push notification
    admin.messaging().sendToDevice(notification_data.device_token, payload).then(function(res) {
        
        response.send(JSON.stringify({'has_notification': true})); // inform the app that a notification was sent
    })
    .catch(function(error) {
        response.send(JSON.stringify(error)); // send the push notification error to the app
    });

}else{
    response.send(JSON.stringify({'has_notification': false})); // inform the app that a notification was not sent
}

更新应用程序代码

之前,您设置了应用程序,以便它能够接收推送通知。这一次,您将添加代码,以便您的应用程序可以处理这些推送通知并将它们显示给用户。 

接收推送通知

为了接收推送通知,您需要做的第一件事是更新 firebase.init() 函数以包含用于接收设备令牌的***器:

onPushTokenReceivedcallback: function(token) {
    // temporarily save it to application settings until such time that 
    // the user logs in for the first time
    applicationSettings.setString('device_token', token);
},

此函数只执行一次,因此您必须使用应用程序设置在本地保存令牌。稍后,这将允许我们在用户第一次登录时获取设备令牌。如果您还记得上一个教程,我们将在用户首次登录时将其数据保存到 Firebase。

接下来,您可以添加接收通知的***器。这将显示一个使用消息的标题和正文作为内容的警告框:

onMessageReceivedCallback: function(message) {
    dialogs.alert({
        title: message.title,
        message: message.body,
        okButtonText: "ok"
    });
},

将设备令牌保存到 Firebase

Firebase 云消息传递在向特定设备发送推送通知时需要设备令牌。由于我们已经在使用 Firebase,我们只需将设备令牌与用户数据一起保存。为此,您需要编辑用于保存用户数据的代码以包含我们之前获得的设备令牌:

if(firebase_result.value == null){ 

    var device_token = applicationSettings.getString('device_token');

    var user_data = {
        'uid': fb_result.uid,
        'user_name': fb_result.name,
        'profile_photo': fb_result.profileImageURL,
        'device_token': device_token 
    };

}

触发推送通知

发生以下两种情况之一时会触发推送通知:

  • 当用户打破他们当前的记录时

  • 当用户的一个朋友打破他们的记录并获得第一名时

第一个很简单,所以真的不需要额外的设置。但是对于第二个,您需要做一些工作。首先,您必须编辑身份验证状态更改时的代码。从 Facebook 结果中提取好友 ID 后,您必须使用应用程序设置保存好友 ID。

// extracting the friend IDs from the Facebook result
var friends_ids = r.data.map(function(obj){
    return obj.id;
});

// save the friend IDs
applicationSettings.setString('friends_ids', JSON.stringify(friends_ids));

friends_ids.push(user[user_key].id);

接下来,更新用户何时停止跟踪他们的步行的代码。在构建用于更新用户的用户数据的代码之后,从应用程序设置中获取好友 ID,并将其包含在包含触发推送通知的请求数据的对象中。

// construct the user data for updating the user's distance and steps
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;

// get friend IDs
var friends_ids = JSON.parse(applicationSettings.getString('friends_ids'));

var request_data = {
    'id': user_data[user_key].id,
    'friend_ids': friends_ids.join(','),
    'steps': total_steps
};

向您之前创建的 Firebase Cloud Functions 端点发出请求。一旦返回成功响应,用户的数据才会在 Firebase 数据库中更新。 

http.request({ 
    url: "https://us-central1-pushapp-ab621.cloudfunctions.net/init_push", 
    method: "POST",
    headers: { "Content-Type": "application/json" },
    content: JSON.stringify(request_data) 
}).then(function (response) {
   
    var statusCode = response.statusCode;
    if(statusCode == 200){
        // update the user's data on Firebase
        firebase.update(
            '/users',
            user_data
        ); 

    }

}, function (e) {
    console.log('Error occurred while initiating push: ', e);
});

测试推送通知

您可以通过首先从模拟器或设备卸载应用程序来测试推送通知的发送。这使我们能够正确触发获取设备令牌的功能。请务必添加console.log 以输出设备令牌:

onPushTokenReceivedCallback: function(token) {
    applicationSettings.setString('device_token', token);
    console.log('device token: ', device_token); // <-- add this
}

当设备令牌在 NativeScript 控制台中输出时,复制它,单击 Firebase 应用仪表板上的数据库 菜单,并将其作为设备令牌添加到应用程序的所有用户。用作device_token 属性名称。

要触发推送通知,您可以使用curl 向POST Firebase 函数端点发出请求:

curl -X POST -H "Content-Type:application/json" YOUR_FIREBASE_FUNCTION_ENDPOINT -d '
{"id":"ID OF A FIREBASE USER", 
"steps":NUMBER_OF_STEPS, 
"friend_ids":"COMMA,SEPARATED,FIREBASE,USER_IDs"}'

如果你没有安装 curl,你可以使用Postman App 发送请求。对请求使用以下设置:

  • 请求方法: POST

  • URL: 您的 Firebase 函数端点

  • 标题键: Content-type

  • 标头值: application/json

  • 身体: 

{"id":"ID OF A FIREBASE USER", "steps":NUMBER_OF_STEPS, "friend_ids":"COMMA,SEPARATED,FIREBASE,USER_IDs"}

触发后,您将看到类似于以下内容的输出:

使用NativeScript编写实时应用程序:推送通知  第3张

如果应用当前未打开,您将在通知区域看到通知:

使用NativeScript编写实时应用程序:推送通知  第4张

结论

恭喜!您终于完成了健身应用程序。在四个教程的过程中,您构建了一个使用 Google 地图、SQLite、Firebase 实时数据库和 Firebase 云消息传递的 NativeScript 应用程序。现在,您已经为构建使用这些技术的 NativeScript 应用程序打下了良好的基础。


文章目录
  • 你将要创造什么
  • 设置项目
  • 运行项目
  • 设置 Firebase 云功能
  • 添加服务器代码
    • 创建 Firebase 函数
    • 获取用户和好友数据
    • 构造通知负载
    • 发送通知
  • 更新应用程序代码
    • 接收推送通知
    • 将设备令牌保存到 Firebase
    • 触发推送通知
  • 测试推送通知
  • 结论