我是Swift开发人员,不是后端开发人员。这实际上是下面用粗体显示的3个不同的问题,但它们都是相互依赖的。任何类似问题的堆栈溢出答案都足以让我开始
@followers
|
kim_userId // kimKardashian
-userId_0: 1
-... // every user in between
-userId_188_million: 1
现在我正在使用一种非常低效的方式来发送大规模推送通知:
@IBAction func postButtonTapped(button: UIButton) {
let postsRef = Database.database().reference().child("posts").child(kim_userId).child(postId)
postsRef.updateChildValues(postDictionary, withCompletionBlock: { (err, _)
if let error = error { return }
// post was successful now send a push notification to all of these followers
self.fetchFollowers(for: kim_userId, send: postId)
})
}
func fetchFollowers(for userId: String, send newPostId: String) {
let followersRef = Database.database().reference().child("followers").child(userId)
followersRef.observe(.childAdded) { (snapshot) in
let userId = snapshot.key
self.fetchDeviceToken(forFollower: userId, send: newPostId)
}
}
func fetchDeviceToken(forFollower userId: String, send newPostId: String) {
let usersRef = Database.database().reference().child("users").child(userId)
usersRef.observeSingleEvent(of .value) { (snapshot) in
guard let dict = snapshot.value as? [String: Any] else { return }
guard let deviceToken = dict["deviceToken"] as? String else { return }
self.sendPushNotification(toFollower: userId, with: deviceToken, send: newPostId)
}
}
func sendPushNotification(toFollower: userId, with deviceToken: String, send newPostId: String) {
var apsDict = [String: Any]()
// newPostId and whatever other values added to the dictionary
guard let url = URL(string: "https://fcm.googleapis.com/fcm/send") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: apsDict, options: [])
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("key=(my_serverKey...)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
do {
if let jsonData = data {
if let jsonDataDict = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.allowFragments) as? [String: AnyObject] {
print("Received data:n(jsonDataDict))")
}
}
} catch let err as NSError {
print(err.debugDescription)
}
}
task.resume()
}
例如,金·卡戴珊在Instagram上有1.88亿粉丝,当她发布一些东西时,它会同时发给所有粉丝。我目前的做法不是该走的路。我很确定这是云函数的情况,但我对云函数了解不够,所以我正在考虑从哪里开始。
-如何从iOS应用程序中连接云功能
-无论我必须从";追随者";ref,然后我必须从他们的";用户";ref,我不确定从哪里开始
-如何在云功能内发送推送通知代码?我找到了这个答案,但它在javascript中。我不知道javascript,但我知道一点Node.js
PostVC:
@IBAction func postButtonTapped(button: UIButton) {
let postsRef = Database.database().reference().child("posts").child(kim_userId).child(postId)
postsRef.updateChildValues(postDictionary, withCompletionBlock: { (err, _)
if let error = error { return }
// post was successful now connect to Cloud Functions so that a mass push notification can be sent
self.codeToConnectWithCloudFunctions(for: kim_userId, send: postId)
})
}
func codeToConnectWithCloudFunctions(for userId: String, send newPostId: String) {
// 1. how do I get each of her followers
// 2. how do I get each of their deviceTokens
// 3. how do I send the push notification
}
任何有类似答案的链接都足以让我开始。我可以从那里进行更多的挖掘,并根据我发现的提出更具体的问题
如何从iOS应用程序中连接云功能
您可以通过与调用任何API相同的方式调用云函数,您必须将云函数设计为可调用函数,您可以在本文档中找到更多关于它们的详细信息,以及如何用Swift和其他语言设置这些功能。
无论我必须从";追随者";ref,然后我必须从他们的";用户";ref,我不确定从哪里开始和在Cloud Functions内部如何发送推送通知代码?我找到了这个答案,但它在javascript中。我不知道javascript,但我知道一点Node.js
这两个问题可以通过这个社区答案一起回答,该答案指出您应该将Firebase云消息集成到您的iOS应用程序中,并提供有关该主题的完整文档的链接。此外,您可以在本文档中找到如何向多个设备发送通知,在其中,您还可以找到使用Admin SDK在云功能本身中使用的代码示例。
注意:云函数可以用Node.js、Go、Java和Python编写,云函数的所有示例代码都是用这些语言编写的。
以下是如何使用云函数将数据从iOS应用程序发送到RealTimeDatabase:
在你开始之前,你需要安装node.js/npm
,这很容易做到,遵循这个youtube
1-假设您安装了node
,请转到Firebase控制台>选择右侧的CCD_ 3>Upgrade
>Pay as you go Blaze Plan
>Get Started
>Continue
>Finish
2-打开终端并输入$npm install -g firebase-tools
(如果已经安装了,则可以跳过此步骤)。如果得到错误:EACCES:权限被拒绝响应,则输入$sudo npm install -g firebase-tools
并输入您的cpu密码以继续。如果出现错误,更新版本的npm
将需要此,而不是$ sudo npm install --location=global firebase-tools
3-完成后,输入$npm --version
查看您安装了哪个版本(如果您想要节点版本,则使用$ node -v
)
4-创建一个空文件夹,并将其命名为Cloud_Functions之类的东西。将该文件夹拖动到下面的步骤5中。您将在此Cloud_Functions文件夹中执行以下所有步骤。
5-转到你Xcode项目所在的主文件夹,我的矿在我的桌面上,名为fooProject
6-cd放入该文件夹$cd fooProject
,然后$cdCloud_Functions
7-在终端中输入$pwd
,因为如果您必须在Cloud_Functions文件夹中进行此工作
8-在终端中输入$firebase login
(输入您的登录凭据并按enter)
9-假设您在正确的文件夹中,在终端中输入:
$firebase init functions
10.A-你可能会先看到这个选项(或者根本看不到):
要为此文件夹设置哪些Firebase CLI功能?按空格键选择功能,然后按Enter键确认您的选择
使用向上/向下键选择Functions: Configure and deploy Cloud Functions
,首先按SPACE BAR
,然后按ENTER
。如果先按Enter键,则此操作无效,必须先按空格键,然后再按Enter键。如果此选项没有像在一个项目中那样出现,在另一个项目上没有出现,然后在另一项目上没有再次出现,则下面的10.B肯定会首先出现。
10.B-您可能会在第二个(或第一个)Use an existing project
中看到此选项,按enter
11-下一个选项是Select a default Firebase project for this directory
,使用上/下箭头选择您的项目,按enter
12-下一个选项是What language would you like to use to write Cloud Functions?
,两个选项是Javascript和typescript,我用上/下箭头选择Javascript
,然后按enter
13-下一个选项是Do you want to use ESLint to catch probable bugs and enforce style?
我输入了n
并按下回车键。这些规则非常严格,如果事先不知道规则,那么在第22步部署时会出现一堆错误。如果您不知道它们,我建议您选择n
作为无
14-下一个选项是Functions
0我输入了y
并按下输入
15-在它完成安装后,下一件事不是一个选项,而是一个更新到最新版本的建议,并建议输入$npm install -g firebase-tools
。我一直有错误,所以我跳过了这一步,因为这与步骤2 相同
16-当仍然在Cloud_Functions
文件夹中时,运行$ls
,您将看到一个functions
文件夹。运行$cd functions
,因为下一步必须在functions
文件夹中进行。
17-$pwd
让你在functions
文件夹
18-下一次运行$npm i --save firebase-functions@latest
19-接下来运行$open index.js
打开index.js文件。Sublime 中自动打开的矿山
20-这是一个简单的youtube视频,介绍如何处理index.js
文件中的现有代码。或者,您可以简单地取消对所有代码的注释,确保按save(命令+S),然后运行$firebase deploy --only functions
。几分钟后,您应该会得到一份Deploy complete!
声明
21-你可以注释掉示例代码,这是从我的iOS应用程序中的视图控制器接收一些数据的代码(步骤25)。确保您的Firebase规则通过控制台允许写入您正在写入的任何ref,并确保已设置计费(步骤1),因为它在您第一次部署时验证计费(步骤22)。在index.js
文件中输入:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.updateSneakerTypeToPostsRef = functions.https.onCall((data, context) => {
const postId = data.postId; // this will be abc123
const userId = data.uid; // this will be whatever the user's id is
const sneakerName = data.sneakerName; // this will be Adidas
const receivedTimeStamp = Date.now(); // Data.now() is how you receive the timestamp in Javascript/Node
// this is just a print statement
console.log("received values =" + " | postId: " + postId + " | userId: " + userId + " | sneakerName: " + sneakerName + " | timeStamp: " + receivedTimeStamp);
// this is the database path: posts/postId/userId in step 25 and I'm going to add the *sneakerName:Adidas* and *receivedTimeStamp* to it
var postsRef = admin.database().ref('/posts/' + postId + '/' + userId);
return postsRef.set({ "sneakerName": sneakerName, "timeStamp": receivedTimeStamp })
.catch((error) => {
console.log('ERROR - updateSneakerTypeToPostsRef() Failed: ', error);
});
});
22-保存上面的文件,现在在终端中输入下面,冒号后面的部分是步骤21中exports.
函数的名称,它必须是相同的确切名称:
$firebase deploy --only functions:updateSneakerTypeToPostsRef
。这将只部署此1函数。如果您有多个功能,则使用$firebase deploy --only functions
一次部署它们所有
如果您删除了初始示例代码,您将得到响应:以下函数在您的项目中找到,但在您的本地源代码中不存在:helloWorld(us-central…)如果您正在重命名函数或更改其区域,建议您在删除旧函数之前先创建新函数,以防止事件丢失。欲了解更多信息,请访问https://firebase.google.com/docs/functions/manage-functions#modify?是否继续删除?选择"否"将继续执行其余部署*您可以输入no
来删除它,也可以输入yes
来保留它,这无关紧要。无论哪种方式,请稍后按Enter键。
这花了大约3分钟的时间完成,但当它完成时,我得到了functions[updateSneakerTypeToPostsRef(us-central4)]: Successful create operation. Deploy complete!
,我在下面输入它只是为了获取日志信息:
$firebase functions:log
//这是日志数据
现在可以从iOS应用程序内部连接到云功能
23-cd到实际的Xcode项目,打开你的Podfile并放入pod 'Firebase/Functions'
,然后安装$pod install
24-安装后,转到任何视图控制器并将import Firebase
添加到文件顶部,然后将此行添加为类属性lazy var functions = Functions.functions()
25-以下是如何将数据发送到index.js
文件内的函数(步骤21)
import Firebase
lazy var functions = Functions.functions()
@IBAction func buttonTapped(_sender : AnyObject){
sendDataToCloudFunction()
}
func sendDataToCloudFunction() {
let data: [String: Any] = ["postId": "abc123",
"uid": Auth.auth().currentUser!.uid,
"sneakerName": "Adidas"]
let exportsName = "updateSneakerTypeToPostsRef" // *** this HAS TO BE the SAME exact function name from steps 21 and 22 ***
functions.httpsCallable(exportsName).call(data) { (result, error) in
print("Function returned")
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
print(code.debugDescription)
print(message.debugDescription)
print(details.debugDescription)
}
print(error.localizedDescription)
return
}
if let res = result {
print("------->", res)
}
if let operationResult = (result?.data as? [String: Any])?["operationResult"] as? Int {
print("(operationResult)")
}
}
}
26-燃烧基地内部的结果看起来像
@posts
@abc123
@whatever_the_userId_is...
-sneakerName: "Adidas"
-timeStamp: 1595874879.9619331
这是一件单独的事情,但您也应该确保您的应用程序引擎和云功能位于同一区域。点击此处阅读更多
你不能通过终端打印出你的云功能,但你可以在
Google Cloud Console
中看到它们,如本答案所述