簡體   English   中英

Firebase 雲消息傳遞 - Django - 我如何服務工作者?

[英]Firebase Cloud Messaging - Django - how do I service worker?

從溫和理解的地方更新:

我已經閱讀了很多關於 Service Workers 的文章,並將我正在從事的項目推進到了我寫這篇文章的時候。

我在這里探索的主要問題(從域的根目錄獲取firebase-messaging-sw.js服務)由下面的ServiceWorkerView解決。

有趣的事實:事實證明,從域的根目錄提供firebase-messaging-sw.js的原因是 Service Worker 的控制范圍由 URL 定義。 所以,雖然:

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

http://whatever.com/static/firebase-messaging-sw.js只能控制/static/下的所有內容(在這種情況下,只有 Django 提供的靜態資源)。 即使 JS 文件是靜態的,它也需要控制該路徑之外的頁面。

學習 Service Worker 的好起點

原問題:

如何讓 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')

網址.py:

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

現在 url 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")

我得到的錯誤是:

Uncaught (in promise) TypeError: Failed to register a ServiceWorker: 獲取腳本時收到錯誤的 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>

我嘗試按照https://firebase.google.com/docs/cloud-messaging/js/client 上的說明添加manifest.json

它目前由我的靜態文件提供,並在注冊和發送頁面中鏈接

我的控制台中的錯誤:

Uncaught (in promise) TypeError: Failed to register a ServiceWorker: 獲取腳本時收到錯誤的 HTTP 響應代碼 (404)。

獲取腳本時收到錯誤的 HTTP 響應代碼 (404)。

無法加載資源:net::ERR_INVALID_RESPONSE

firebase-messaging-sw.js:3 未捕獲

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

index.esm.js:1945 未捕獲(承諾)

目的

瀏覽器錯誤消息:

“注冊ServiceWorker失敗:ServiceWorker腳本評估失敗”

代碼:

“消息/失敗的服務人員注冊”

信息:

“消息:我們無法注冊默認的服務工作者。注冊服務工作者失敗:服務工作者腳本評估失敗(消息/失敗-serviceworker-registration)。”

堆:

“FirebaseError: Messaging: 我們無法注冊默認的 Service Worker。無法注冊 ServiceWorker:ServiceWorker 腳本評估失敗 (messaging/failed-serviceworker-registration)。↵ at https://www.gstatic.com/firebasejs/5.2 .0/firebase-messaging.js:1:34104 "

無法為firebase-messaging-sw.js提供服務的問題可以通過創建ServiceWorkerView來直接GET文件並硬編碼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的原因是 Service Worker 的控制范圍由 URL 路徑定義。 Service Worker 可用的路徑下的所有內容都在其控制之下。


404可能是由於device_registration.html的 javascript 錯誤device_registration.html 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()的問題在於,從 promise 更改表單中元素的代碼不完整。 調試后它會很好用。

我喜歡 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/;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM