As part of
the ongoing effort to modernize my technology stack, the question on
notifications constantly surfaces. Today the de facto solution for them on Android
is to use Firebase Cloud Messaging (FCM). As I’m trying to use C# for
everything I’ll be using Xamarin.Android. Microsoft has relatively good documentation
on FCM, so I won’t be repeating it. Instead, this post is primarily about
venting about Android development, even after Xamarin makes slightly more
bearable. This post it not to be taken as general indication of, well,
anything.
* * *
So. I
create a new basic Android application. I try to register a new project in Firebase
and add my server as a client application, but Google’s documentation is out-of-sync,
so I don’t find what I’m looking for. I finally manage so stumble to the right
page and can get to work.
I create a
scaffolding for my notifications server and try to send the device token to it
from the mobile application. It fails. The documentation uses a deprecated API,
but that’s not it. Okay. I’ll just look at the logs. But hah, fuck that. I didn’t
start the application via the debugger, so I don’t get to filter the logs by application.
I have to use the command-line version of logcat, and instead I’m flooded with
messages from AfterImageCompositionService and touch debugger and friends. I
can’t even filter the logs sensibly by my log tags, because they were changed
years go to be limited to a something like 23 characters. But I finally find
the error: I can’t use plaintext HTTP anymore on Android by default. Not even
on local network! The “correct” way would seem to define some kind of complex security
policy, so I just go for the alternative of slapping usesCleartextTraffic="true" to the manifest.
And things
work, yay. I can send notifications, and they appear on the phone without even
having to have the application running! But then, as stated in the
documentation, I try to send them when the application is running. And they won’t
work. So I have to manually construct the notification (though, as stated in documentation),
and hope that it matches is appearance to the “built-in” one.
And then
the documentation starts to fall apart. Starting with just minor things, like
not stating that icons should have an alpha channel, or otherwise they appear
as blank squares (docs were written for older Android). Then larger things, like
when with the otherwise very clear testing instructions there are suddenly no
instructions to test those foreground notifications. Well, that is because they
won’t work if just following the documentation. And by now I’ve already forgotten
what I had to do to somewhat fix them.
And testing
out the code creating the notification needs few more iterations than I’d be
comfortable. Building, deploying and running the application takes actually
quite a bit of time, even when I have the relevant acceleration settings enabled.
That is, using shared runtime and only deploying changed modules of the
application. It also bugs me that the shortcut for the application keeps
occasionally disappearing from my launcher. Then I finally look into this more,
and find out that Xamarin, at least on Visual Studio 2019, doesn’t honour those
settings, and just uninstalls and install the application every fucking time.
But oh, it
gets better. As I try to test both background and foreground notifications, I
have to occasionally close the app so that it is no longer running. I do this
by pressing the “Close all” button on my Samsung phone. And the notifications
won’t work. Little did I know that there was some OEM-fuckery at work. Apparently
closing the application this way is the same as killing it (at least as far as OS
state-keeping is concerned). This sets a special flag indicating that the app
was killed, and the OS-level Firebase service won’t
deliver messages to applications that have been killed. vittumitäpaskaa
After I’ve
regained my composure I move to the next feature on the list. Showing an image
attached to the notification. The documentation
states that this is as simple as setting the image URL in the notification payload
to a valid HTTPS image. Firebase console even shows a preview of the image!
The
documentation was wrong. I spend one full day trying to get the image to work,
and it still doesn’t work. I tried doing it in so many different ways, via both
generic and Android-specific settings, via the old and the new Firebase API,
via managed code and by hand, via my server or directly, or via the Firebase
console. Nothing works. I’m starting to suspect that might be Xamarin’s fault
at this point. Couldn’t really find any documentation confirming or denying it.
Couldn’t even find any documentation how the Firebase library is supposed to work
at application-level on plain Android. Is it really operating-system level, or
is it just some code included by the library to the application, and then it
really is the application showing the notification even when it wasn’t running?
And maybe with Xamarin no-one bothered to implement the code for showing the
image. Maybe I’ll never know. I could create a new Android Java application,
but I really can’t be bothered to do it… Thanks to C#, I’ve started to hate the
clunky syntax of Java and other tooling more and more.
So many unnecessary
hardships for trying to get even the basic application working… Next is the fun
of trying to keep the device’s Firebase token in sync with the server. Apparently,
it can occasionally change, and must be sent to the server again. But what if
the network doesn’t work right then? I’ll have to manually build to scaffolding
to manually schedule background work and keep it retrying until it works.
And then
finally I get to implementing more server-side stuff, like removing the device
token from the server should the application get uninstalled. Or delivery
notifications! Those would be where things start to really get useful! Maybe I
can also start to implement notification storage to the device, so that I can
filter notifications by their read-status, and not show notifications that were
resent due to network errors. And then maybe implement some kind of caching and
stuff, and data messages. Then I’ll probably have to implement downloading and
showing attached images myself, but on the other hand then it should finally
start working. And then have a nice application that has a GUI list showing both
all the past notifications, but also those that are unread. And then the general
server-lead notification system can be expanded to span other devices, too.
Like lightbulbs! And the add some service health notifications from other
services I’ve been planning or implementing. And general ones too, like package
or price tracking.
* * *
Package
tracking was actually the reason I finally looked into this topic. Matkahuolto
didn’t have notifications when new info appeared in tracking, like some other
companies do. So, I made them myself. And despite all those hardships, I
actually got the notifications and tracking working quite OK. Then the funniest
thing happened. Matkahuolto updated their
site like an hour after I got everything working :’D Had to make a quick fix
to the script. Luckily things got easier, as I didn’t have to parse HTML, and could
get JSON instead. Good thing I included error handling to the script. If the
crawl failed 10 times in a row it would send an error notification. And now I have
the LG OLED65E9 TV I ordered :3 Perhaps more on the HDMI 2.1 4k120 fun of the
TV later!
Like I
mentioned earlier, I’m looking to expand to using serverless, so that I won’t
have to use more error-prone cronjobs and such. I’ve also never ran C# code via
cron, and everything has been in Python still. So serverless would enable me to
write these in C#. But there seems to be a partial solution for this problem in
form on LinqPad. I’ve been longing for a serverless platform that made code as
easy to execute as LinqPad. So why not just use it? I even have a Windows PC
constantly running. Of course there is the problem of scripts still maybe
failing randomly and without any automatic restart, but there exists a partial
solution in form of monitoring. I’ve been building some general purpose service
and service discovery code on top of NATS, and maybe that solution could be
used for that, too. A LinqPad script could register itself to that service
discovery / health checking system, and then I’d get notifications if the
script failed in some way! Maybe more of that, too, later. Later as always.
Well, got to have plans? An endless list of things to do, so that I can never feel
satisfied from having done everything.
No comments:
Post a Comment