Implement Web Push notifications to mobile, without browser open

by jj

Software Development Journey Overview

Follow this step-by-step software development journey to see real progress updates, challenges overcome, and practical experience.

Progress Updates (4 total)

Update #1: Implement Web Push notifications to mobile, without browser open

In lieu of a native mobile app, I'd like to experiment implementing Web Push, which supposedly can push notifications to remind users to update their progress just from mobile browsers.

Update #2: Able to request permissions and send user subscription to backend

30% complete
Using swPush and PWA, able to store subscription data which should set me up to push notifications to users. Need to figure out sub expiration and web push from Lambda. Also set up an eventbridge to trigger the notifications on a schedule. Simple invoking seems to work from backend to user endpoints, so VAPID key pair seems to work.
Obstacles Faced: How to handle subscription data? Will VAPID keys generated online be compatible with the front end/back end? How can I add the pywebpush library to an AWS lambda? Can I just use SNS to send the notifications instead of requiring the lambda to do everything? (Seems like it could cause large lambda uptime to send all push requests in a loop)
Looking Back: Definitely use both ng web-push and ng PWA; I was confused which one to add but they're both important. The former helps with subscription and the latter with running the service worker.

Update #3: Push being received on phones after some troubleshooting

85% complete
I was seeing messages come through subscribing to sw.Push.messages, but no notification was popping up. After too much debugging, it turns out my push payload format was incorrect from the backend. Confirmed this works with app closed!
Challenges Overcome: I wasn't sure why I was seeing sW.message, but not notifications displayed. Could have been VAPID key mismatch, or browser specific issues, or something else. To debug, I went into the Service Worker file (ngsw-worker.js) and logged the trace of getting a push notification. In here, I noticed sW was in fact getting the push. Further into the file, I saw notification being displayed as "notification.title", "notification.body". I was missing an outer "notification" key! This seems to be omitted most resources on the subject.
Next Steps: I've created a basic "check who needs a notification query". Now, I need to deploy the "pywebpush" library to a Lambda layer.
Looking Back: The correct format for the push notification payload is: Further into the file, I noticed the expected payload structure is: { "notification": { "title": "title", "body": "body", "icon": "icon" } }, not: { "title": "title", "body": "body", "icon": "icon" }

Update #4: Pywebpush added as Lambda layer

100% complete
Had an interesting problem where cryptography lib installed on MacOS was not compatible with AWS Linux. But, that's been resolved and notifications are working from within Lambda!
Challenges Overcome: I tried a few different approaches to resolving the cryptography incompatibility issue. Ultimately, building the package and specifying the version in a Docker container was the way to go. I had tried bundling them as two separate layers (pywebpush and cryptography), but Lambda didn't recognize the latter to supersede the default for the former. Overcame these compatibility errors: [ERROR] Runtime.ImportModuleError: Unable to import module 'main': /lib64/libc.so.6: version `GLIBC_2.18' not found (required by /var/task/cryptography/hazmat/bindings/_rust.abi3.so) /opt/python/cryptography/hazmat/bindings/_rust.abi3.so: invalid ELF header {}
Looking Back: This was my first time uploading a layer. It's super easy, just grab /site-packages/ contents, put it in a "python" directory, zip that, and upload it to Lambda console. This had also been my first time using Docker, which I avoided doing fearing complexity. It was so easy (thanks chatGPT). I'll put the exact commands below.
Additional Notes: Steps to build pywebpush in Docker on Mac compatible with Amazon Linux: DockFile: # Start from the Ubuntu base image FROM ubuntu:20.04 # Avoid prompts from apt ENV DEBIAN_FRONTEND=noninteractive # Update and install Python 3.8, pip, and zip RUN apt-get update && apt-get install -y \ python3.8 \ python3-pip \ zip \ && rm -rf /var/lib/apt/lists/* # Upgrade pip RUN python3.8 -m pip install --upgrade pip # Create a directory for the Lambda layer WORKDIR /lambda-layer # First, install pywebpush normally to get its dependencies RUN python3.8 -m pip install pywebpush # Now, install all dependencies of pywebpush, except for cryptography, in the target directory RUN python3.8 -m pip freeze | grep -v "cryptography" | xargs -n 1 python3.8 -m pip install --no-deps --target=./python/lib/python3.8/site-packages/ # Manually install a compatible version of cryptography for AWS Lambda RUN python3.8 -m pip install \ --platform manylinux2014_x86_64 \ --implementation cp \ --only-binary=:all: \ --target=./python/lib/python3.8/site-packages/ \ cryptography # Zip the Python packages for the Lambda layer RUN zip -r pywebpush_lambda_layer.zip python Then, run the following commands to zip into a Lambda layer: docker build -t pywebpush-lambda-layer . docker run --name pywebpush-layer-builder pywebpush-lambda-layer docker cp pywebpush-layer-builder:/lambda-layer/pywebpush_lambda_layer.zip .