Firebase云消息传递-Django-如何为工作人员服务?

时间:2018-07-09 22:08:32

标签: javascript django firebase firebase-cloud-messaging pyfcm

从一个比较了解的地方进行更新:

我已经了解了很多有关Service Workers的知识,并且将我正在从事的项目推向了更高的水平。

我在此探讨的主要问题(从域的根获取firebase-messaging-sw.js)已由下面的ServiceWorkerView解决。

有趣的事实:事实证明,从域的根开始提供firebase-messaging-sw.js的原因是服务工作者控件的范围是由URL定义的。所以,而:

http://whatever.com/firebase-messaging-sw.js可以控制一切,

http://whatever.com/static/firebase-messaging-sw.js仅能控制/static/下的所有内容(在这种情况下,只有Django服务的静态资源)。即使JS文件是静态文件,也需要控制该路径之外的页面。

A good starting point for learning about Service Workers

原始问题:

如何让FCM服务工作者(firebase-messaging-sw.js)在Django中工作?

我将djangofcm-django一起使用。

如何从根本上服务firebase-messaging-sw.js

Django默认在路径“ / static /”下提供静态资产。将STATIC_URL更改为“ /”将使firebase-messaging-sw.js可用,但没有其他内容。

我尝试了将以下内容放入urls.py的建议:

url(r'^(?!/static/.*)(?P<path>.*\..*)$', RedirectView.as_view(url='/static/%(path)s'))

虽然显然光荣地使用了正则表达式魔术,但事实证明服务工作者不能在重定向后面。 (我想这也与有趣的事实有关)

我写了一个视图,该视图由urlconf中的显式URL指向。可行。

class ServiceWorkerView(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'fcmtest/firebase-messaging-sw.js')

urls.py:

path('firebase-messaging-sw.js', views.ServiceWorkerView.as_view(), name='service_worker')

现在,网址http://localhost:8000/firebase-messaging-sw.js提供了JavaScript;但是,Firebase抱怨内容类型为text/plain

所以我将视图更改为:

class ServiceWorkerView(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'fcmtest/firebase-messaging-sw.js', content_type="application/x-javascript")

我得到的错误是:

  

未捕获(承诺)TypeError:无法注册ServiceWorker:A   提取脚本时收到错误的HTTP响应代码(404)。

我的firebase-messaging-sw.js(注意,不会打印console.log语句):

importScripts("https://www.gstatic.com/firebasejs/5.2.0/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js");
importScripts("https://www.gstatic.com/firebasejs/5.2.0/init.js");

// Initialize Firebase
var config = {
    apiKey: "AIzaSyBOb5gh1Lry84116M1uvAS_xnKtcWUoNlA",
    authDomain: "pyfcm-5f794.firebaseapp.com",
    databaseURL: "https://pyfcm-5f794.firebaseio.com",
    projectId: "pyfcm-5f794",
    storageBucket: "pyfcm-5f794.appspot.com",
    messagingSenderId: "813943398064"
};
console.log('in service worker - before initializeApp')
firebase.initializeApp(config);
console.log('in service worker - after initializeApp')

const messaging = firebase.messaging();
console.log('in service worker - after firebase.messaging')

// if the app is in the background (user not on page)
messaging.setBackgroundMessageHandler(function(payload) {
    console.log('in service worker - in setBackgroundMessageHandler')
    const title = "Hello World";
    const options = {
        body: payload.data.status
    }
    return self.registration.showNotification(title, options);
});

最后,我的设备注册页面(我不确定如何运行javascript然后提交。form.submit()无效,但这可能是由于其他原因导致的。 (fcm/fcmtest/templates/fcmtest/device_registration.html

<head>
    {% load static %}
    <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>FCM Device Registration</title>

    <!-- update the version number as needed -->
    <script src="https://www.gstatic.com/firebasejs/5.2.0/firebase.js"></script>
    <script>
    // Initialize Firebase
    var config = {
    apiKey: "AIzaSyBOb5gh1Lry84116M1uvAS_xnKtcWUoNlA",
    authDomain: "pyfcm-5f794.firebaseapp.com",
    databaseURL: "https://pyfcm-5f794.firebaseio.com",
    projectId: "pyfcm-5f794",
    storageBucket: "pyfcm-5f794.appspot.com",
    messagingSenderId: "813943398064"
    };

    firebase.initializeApp(config);
    </script>

    <script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-app.js"></script>
    <!-- include only the Firebase features as you need -->
    <script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-auth.js"></script>
    <!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-database.js"></script>-->
    <script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js"></script>
    <!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-storage.js"></script>-->
    <!-- initialize the SDK after all desired features are loaded -->
    <!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/init.js"></script>-->

</head>

<body>

<script>

function deviceRegistration() {
    console.log('in deviceRegistration()')
    firebase.initializeApp(config);
    const messaging = firebase.messaging();

    // public key generated in firebase console
    messaging.usePublicVapidKey("BMEoHrnzLq5WNeyahbSxJNTyS-44bXug2wetxAWVMLMSUIQE0dexhP4pJhcSA-ZlQlneHURmYQcnq9ofym_sStY");
    // console.log('{% static "firebase-messaging-sw.js" %}')
    console.log("/firebase-messaging-sw.js")
    // changed location passed to navigator.serviceWorker.register since I am no longer serving firebase-messaging.js from localhost/static/ (see that url hack)
    // navigator.serviceWorker.register('{% static "firebase-messaging-sw.js" %}')
    navigator.serviceWorker.register("/firebase-messaging-sw.js")
    .then((registration) => {
        console.log('before messaging.useServiceWorker')
        messaging.useServiceWorker(registration);
        console.log('after messaging.useServiceWorker')

        // Request permission and get token.....
        messaging.requestPermission()
        .then(function(){
            console.log("Have Permission");
        })
        .then(function(token) {
            form = document.getElementById("registration_form");

            registration_token = messaging.getToken();
            form.registration_id = registration_token;

            var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") >= -1;
            if (isAndroid) {
                form.type = "android";
            } else {
                var isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
                if (isiOS) {
                    form.type = "ios";
                } else {
                    form.type = "web";
                }
            }

            //form.submit();
        })
        .catch(function(err){
            console.log("Permission denied");
        })
    });

    // request permission to send notifications
    messaging.requestPermission()
        .then(function(){
            console.log("Have Permission");
        })
        .then(function(token) {
            form = document.getElementById("registration_form");

            registration_token = messaging.getToken();
            form.registration_id = registration_token;

            var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") >= -1;
            if (isAndroid) {
                form.type = "android";
            } else {
                var isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
                if (isiOS) {
                    form.type = "ios";
                } else {
                    form.type = "web";
                }
            }

            //form.submit();
        })
        .catch(function(err){
            console.log("Permission denied");
        })

    // if user is on the page then show message directly instead of a notification
    messaging.onMessage(function(payload) {
        console.log('payload: ', payload);
    });

}

</script>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}


<form id="registration_form" method="post">{% csrf_token %}
    <input id="name" type="text" />
    <input id="type" type="hidden" />
    <input id="user" type="hidden" value="{{ user.id }}" />
    <input id="registration_id" type="hidden" />
    <input id="btn_register" type="button" value="Register" onclick="deviceRegistration();" />
</form>

</body>

我尝试按照上的说明添加manifest.json https://firebase.google.com/docs/cloud-messaging/js/client

当前从我的静态文件中提供,并在注册和发送页面中链接

控制台中的错误:

  

未捕获(承诺)TypeError:无法注册ServiceWorker:A   提取脚本时收到错误的HTTP响应代码(404)。

     

提取脚本时收到错误的HTTP响应代码(404)。

     

无法加载资源:net :: ERR_INVALID_RESPONSE

     

firebase-messaging-sw.js:3未抓到

     
    

(匿名)@ firebase-messaging-sw.js:3

  
     

index.esm.js:1945未发现(承诺)

     
    

对象

         
      

browserErrorMessage:

             
        

“无法注册ServiceWorker:ServiceWorker脚本评估失败”

      
             

代码:

             
        

“消息/服务工作者注册失败”

      
             

消息:

             
        

“消息传递:我们无法注册默认服务人员。无法注册ServiceWorker:ServiceWorker脚本评估失败(消息/服务服务工作者注册失败)。”

      
             

堆栈:

             
        

“ FirebaseError:消息:我们无法注册默认服务人员。无法注册ServiceWorker:ServiceWorker脚本评估失败(消息/失败-serviceworker-registration)。↵位于https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js:1:34104

      
    
  

2 个答案:

答案 0 :(得分:0)

无法解决firebase-messaging-sw.js的问题,可以通过直接创建ServiceWorkerViewGET文件并对URLconf进行硬编码来解决。

fcm / fcmtest / views.py:

class ServiceWorkerView(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'fcmtest/firebase-messaging-sw.js', content_type="application/x-javascript")

fcm / fcmtest / urls.py

app_name = 'fcmtest'
urlpatterns = [
    ...
    path('firebase-messaging-sw.js', views.ServiceWorkerView.as_view(), name='service_worker')
]

从域的根开始服务firebase-messaging-sw.js的原因是服务工作者控件的范围是由URL路径定义的。 Service Worker可用路径下的所有内容均受其控制。


404可能是由于device_registration.html中的javascript错误。已引用config,但尚未分配给它。

function deviceRegistration() {
    firebase.initializeApp(config);

此外,使用Firebase Cloud Messaging进行此操作也没有必要(甚至有问题):

navigator.serviceWorker.register("/firebase-messaging-sw.js")
.then((registration) => {
    messaging.useServiceWorker(registration);
})

使用firebase.initializeApp(config);


最好从根本上服务manifest.json


form.submit()的问题在于,从诺言更改形式中的元素的代码不完整。调试后,它将很好用。

答案 1 :(得分:0)

我喜欢Inversus所做的事情,因为它可以在dev / test / prod中使用。话虽这么说,在生产中,我选择让Nginx服务firebase-messaging-sw.js文件。 。

    # Firebase Cloud Messaging (FCM) requires this file to be served from
    # your root directory
    location =/firebase-messaging-sw.js {
        root /home/ubuntu/yourpath/yourproject/FCM/;
    }