Rails 带有 react-native-webview 应用程序和 firebase 消息传递的 turbolinks 服务器
Rails turbolinks server with react-native-webview app and firebase messaging
我有以下设置:
一个 rails 服务器,它有一个使用 devise gem 的基本用户登录。
我在那里定义了一个 User
和一个 Device
模型,其中每个用户可以通过用户的 has_many
关系拥有多个设备。 Device
模型有一个单一的属性——一个令牌,我会用它来发送推送通知给 rpush gem.
使用 react-native-webview package and the react-native-firebase/messaging 包的 react-native 应用程序。问题是,我真的不知道如何将 firebase 设备令牌正确发送到服务器。
到目前为止,我已经将 rails 设计 registrations#new
视图覆盖为以下内容:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<%= f.fields_for :devices, @user do |f| %>
<div class="field">
<%= f.hidden_field :token, {value: nil} %>
</div>
<% end %>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
在这里你可以看到我为令牌添加了一个隐藏字段,当我使用以下代码进入 /users/sign_up
页面后,我将其插入到 react-native 应用程序中:
import React, { useState } from "react";
import { WebView } from "react-native-webview";
import messaging from '@react-native-firebase/messaging';
const MyWebView = () => {
const [uri] = useState("http:\/\/10.0.2.2:3000");
const [webViewRef, setWebViewRef] = useState(null);
const postMessageThatTurbolinksLoadOccured = `
document.addEventListener("turbolinks:load", () => {
window.ReactNativeWebView.postMessage("turbolinks:load");
})`;
function onMessage(obj) {
const event = obj.nativeEvent;
if(event.data != "turbolinks:load") return;
if(event.url==`${uri}/users/sign_in` || event.url==`${uri}/users/sign_up`) {
messaging().getToken().then(token => {
const insertTokenCode = `
document.getElementById("user_devices_attributes_0_token").value = "${token}";
`;
webViewRef.injectJavaScript(insertTokenCode);
})
}
}
// This is here only temporarily
messaging().onMessage(remoteMessage => {
Alert.alert(remoteMessage.notification.body);
})
return (
<WebView
ref={setWebViewRef}
source={{ uri: `${uri}/users/sign_in` }}
injectedJavaScript={postMessageThatTurbolinksLoadOccured}
onMessage={onMessage}
/>
);
};
export default MyWebView;
这实际上工作正常,但是当我开始测试 rails 应用程序并尝试在规范中设置隐藏字段值时,我得到了一个错误:
Selenium::WebDriver::Error::ElementNotInteractableError:
element not interactable
这让我觉得这种方法很“hacky”。那么有人知道更好的方法吗?
对于同样遇到这个问题的人,我早就想通了,但还没来得及回答这个问题。
我开始使用 firebase 通道,而不是必须在服务器上注册每个设备,而只是将消息发送到通道,这样我就不需要在服务器上保存每个设备 ID。像这样:
- 对于 react-native 应用程序
import { Alert } from "react-native";
import { WebView } from "react-native-webview";
import messaging from '@react-native-firebase/messaging';
const MyView = () => {
const messagingInstance = messaging()
messagingInstance.subscribeToTopic("welcome").then(() => {
messagingInstance.onMessage(message => {
if(message.from == "/topics/welcome") {
Alert.alert(message.notification.body);
messagingInstance.unsubscribeFromTopic("welcome");
}
});
});
return (
<WebView
source={{ uri: `http:\/\/10.0.2.2:3000` }}
/>
);
};
export default MyView;
- 在服务器上,我有一个作业使用 fcm gem
通过通道发送通知
class SendGreetingPushNotificationJob < ApplicationJob
queue_as :default
def perform(*args)
fcm = FCM.new(Rails.application.config.FIREBASE_SERVER_KEY)
fcm.send_to_topic("welcome", notification: {body: "Welcome to MyApp!"})
end
end
我有以下设置:
一个 rails 服务器,它有一个使用 devise gem 的基本用户登录。
我在那里定义了一个 User
和一个 Device
模型,其中每个用户可以通过用户的 has_many
关系拥有多个设备。 Device
模型有一个单一的属性——一个令牌,我会用它来发送推送通知给 rpush gem.
使用 react-native-webview package and the react-native-firebase/messaging 包的 react-native 应用程序。问题是,我真的不知道如何将 firebase 设备令牌正确发送到服务器。
到目前为止,我已经将 rails 设计 registrations#new
视图覆盖为以下内容:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<%= f.fields_for :devices, @user do |f| %>
<div class="field">
<%= f.hidden_field :token, {value: nil} %>
</div>
<% end %>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
在这里你可以看到我为令牌添加了一个隐藏字段,当我使用以下代码进入 /users/sign_up
页面后,我将其插入到 react-native 应用程序中:
import React, { useState } from "react";
import { WebView } from "react-native-webview";
import messaging from '@react-native-firebase/messaging';
const MyWebView = () => {
const [uri] = useState("http:\/\/10.0.2.2:3000");
const [webViewRef, setWebViewRef] = useState(null);
const postMessageThatTurbolinksLoadOccured = `
document.addEventListener("turbolinks:load", () => {
window.ReactNativeWebView.postMessage("turbolinks:load");
})`;
function onMessage(obj) {
const event = obj.nativeEvent;
if(event.data != "turbolinks:load") return;
if(event.url==`${uri}/users/sign_in` || event.url==`${uri}/users/sign_up`) {
messaging().getToken().then(token => {
const insertTokenCode = `
document.getElementById("user_devices_attributes_0_token").value = "${token}";
`;
webViewRef.injectJavaScript(insertTokenCode);
})
}
}
// This is here only temporarily
messaging().onMessage(remoteMessage => {
Alert.alert(remoteMessage.notification.body);
})
return (
<WebView
ref={setWebViewRef}
source={{ uri: `${uri}/users/sign_in` }}
injectedJavaScript={postMessageThatTurbolinksLoadOccured}
onMessage={onMessage}
/>
);
};
export default MyWebView;
这实际上工作正常,但是当我开始测试 rails 应用程序并尝试在规范中设置隐藏字段值时,我得到了一个错误:
Selenium::WebDriver::Error::ElementNotInteractableError:
element not interactable
这让我觉得这种方法很“hacky”。那么有人知道更好的方法吗?
对于同样遇到这个问题的人,我早就想通了,但还没来得及回答这个问题。
我开始使用 firebase 通道,而不是必须在服务器上注册每个设备,而只是将消息发送到通道,这样我就不需要在服务器上保存每个设备 ID。像这样:
- 对于 react-native 应用程序
import { Alert } from "react-native";
import { WebView } from "react-native-webview";
import messaging from '@react-native-firebase/messaging';
const MyView = () => {
const messagingInstance = messaging()
messagingInstance.subscribeToTopic("welcome").then(() => {
messagingInstance.onMessage(message => {
if(message.from == "/topics/welcome") {
Alert.alert(message.notification.body);
messagingInstance.unsubscribeFromTopic("welcome");
}
});
});
return (
<WebView
source={{ uri: `http:\/\/10.0.2.2:3000` }}
/>
);
};
export default MyView;
- 在服务器上,我有一个作业使用 fcm gem 通过通道发送通知
class SendGreetingPushNotificationJob < ApplicationJob
queue_as :default
def perform(*args)
fcm = FCM.new(Rails.application.config.FIREBASE_SERVER_KEY)
fcm.send_to_topic("welcome", notification: {body: "Welcome to MyApp!"})
end
end