Brainstorming on a mobile companion library for LiveView

Hey everybody. I’m currently working on the reimplementation of an app and we’re using phoenix coupled with Turbo and Stimulus. The only reason we didn’t went with LiveView is turbo-ios which is a fantastic library for a native iOS client: it’s very lightweight (the whole “framework” is only around 3000 LOC) and allows you to build hybrid apps fast.

The idea of this companion library (it also exists for android, too) is to have native navigation and web content. The UX is really great, since turbo will cache a lot and hence navigation feels instant in many cases. For the most part it feels like a native app. You can also simply mix in native views easily (for example maps, code scanner, login screen, or whatever makes sense for your application).

The downside to all this is: while the programming model, of only having to send stateless html pages over the wire, seems very simple at first, it gets really, really hairy after a while. Breaking the application down is done via turbo-frames which you can update in place through “turbo-streams” (which we feed through phoenix channels). You also have to always pick the correct http verb when sending data so that turbo will react the way you intended - which is not always as easy as it sounds.

Enough praise/rant, I’d like to build something like turbo-ios/turbo-android but for LiveView. I think the main features would need to be:

  • Native navigation patterns (one web view that gets reused and rendered inside a native navigation stack)
  • Patching native components through LV
  • “caching” already visited pages (i. e. display screenshots/cached html of the last visit even when offline)

I could have started by simply forking turbo-ios but I don’t know enough about the internals of LiveView to decide if this is something that is feasible at all or if there are currently some properties preventing my envisioned use cases.

Also I’d like to learn about prior art in this space (for example, I know about elixir-desktop which is very, very interesting, but not what I’m after).

10 Likes

This sounds really cool and I was going to suggest you look at Elixir Desktop… but looks like you’re already aware of it :smiley: Any reason in particular why it’s not what you’re after? Would your project just be for iOS/Android?

Either way good luck, I’m sure a lot of people will be interested in seeing what you come up with :023:

6 Likes

Yes! elixir-desktop is just the opposite of what I’m after: it is an app running on the users device rendering all UI elements with web technologies.

What I want to achieve instead is a wrapper using platform native, navigational UI elements and displaying content and cross platform UI elements generated by a central server. (Like described here for Turbo: Basecamp 3 for iOS: Hybrid Architecture - Signal v. Noise)

And this also answers the second question:

Probably, since I don’t have use for anything else currently, but in the end it would be possible to write such a wrapper for any platform that can display a web view. The main problem will be to define the api making the communication between LV and the “native” components feasible.

5 Likes

A few thoughts (I may be out of my depth):

If you have web views you could use js hooks. There exists something similar with React (have not played with it). But: the client (the webview) needs to interpret what the server wants. So you need a bridge (in fact data that can be interpreted).

I guess the same approach could be taken with a native app.so the LivevView acts like a server"and owns the state. The reply tells the app what to display.

1 Like

Interesting… Not sure about rendering native UI elements using LiveView, but for interacting with device feature via JS maybe you could reuse Cordova’s plugins?

1 Like

And there’s also https://capacitorjs.com by Ionic

And regarding UI, if you’re satisfied with using a web view (at least for some parts of the app), then maybe something like CSS Components - Onsen UI - Onsen UI and JavaScript / Web Components API - Onsen UI - Onsen UI would plug-in in to LiveView nicely

ALERT: Unpopular opinion ahead.

For context I work as a Developer Advocate for Mobile API Security, and at work we need to maintain a lot of quickstarts and examples for hybrid frameworks, and what a poor developer experience it is to work with such frameworks, one worst then the other, but all them are a nightmare to maintain and keep them working on each developers machine, especially when sometime elapsed from its creation.

Not wanting to trash any JS suggestions, but if possible my advice is to stay away from them as much as you can. If you really need to choose one go for the one that as the more direct bridge (doesn’t build on top of others) and has the less complex build system, with fewer dependencies and moving parts.

If you build your own JS bridge, don’t go fancy with JS dependencies. Try instead to consolidate them under your own code. Yes, copy paste whenever the license allows. Managing security advisories in a huge tree of dependencies on JS land becomes sometimes impractical until other packages that aren’t direct dependencies of our project update their dependencies to fix the security advisory.

2 Likes

I need to parrot @Exadra37 on this. The beauty of something like turbo-ios is that it is really lightweight and precisely why we did not go with capacitor, react-native, flutter, etc.

Those frameworks are measured in million lines of code. If something goes astray, I don’t want to be the one trying to fix it. That’s one reason why I decided against using a cross platform solution.

The second reason is that you almost always need platform native code in any sufficiently complex project. And e. g. with cordova you then need to write a wrapper / plugin to make it available - so that’s another indirection.

And last but not least, I enjoy using apps which look and feels like the belong on the specific platform. :slight_smile:

Precisely. The thing I’m most unsure of is how I could hijack the dom diffs that LiveView sends to then update the native components.

1 Like

I also advise against wrapping your entire mobile app in an webview, because if then you need to harden the security of your mobile app you will be out of luck. Believe me that nowadays any “serious” app will need it sooner or later… Its not a question of if, but when. The when is normally when companies discover that they are vulnerable to some attack, or indeed under attack, or worst, already breached. At this point developers need to scramble for finding a solution and the business needs to deal with potential financial losses and angry users that may go away and never comeback.

Plan for your Mobile and API security from day zero, even if you don’t implement it, at least take it in consideration on your software architecture decisions to allow for an easier integration of security measures when you need to scramble to find one that is easy and quick to implement to defend against whatever attack you are suffering. A very important thing to keep in mind is to allow for the HTTP stack being used to be customisable with another one. This will come in hand when you need to add certificate pinning and other more advanced security protections to protect the communication of your mobile app with the APIs it uses.

1 Like

I think it is possible to rewrite the client side of LV in Swift or Kotlin and maintain wire protocol compatibility with the server side LV. It is a much bigger job than turbo-ios but it can be done. The only significant dependency of LV is morphdom which have zero dependency.

If you rewrite it in Swift or Kotlin then morphdom is not needed, because data will be handled outside the webview, or am I misunderstanding something?

I am not familiar with mobile development enough to know; I just intuitively assumed that there is a need to manipulate whatever data structure that backs the webview. What does turbo-ios do?

FWIW, there are some folks working on a library to bring LiveView to JSON objects: GitHub - Miserlou/live_json: LiveJSON - LiveView for JSON. Theoretically this would allow your native app to benefit from the dynamic data updates pushed by the server.

4 Likes

No idea. Not familiar with it at all.

turbo-ios is very much imperative and not reactive at all. So you simply have an API/bridge where you communicate between the web and the native part and other than that you basically have two separate applications.

So my initial idea was to do something similar: simply render hidden components that have a native counterpart and then parse the needed info out of the dom to update the native components. But in order to do that I’d need to hook into the live view lifecycle to know when an update is done. (Thinking about it, this could also be done via LiveJSON, as @yukster suggested)

I also think it is extremely important for such a companion framework to be as simple as possible.

Thanks for all the input :slight_smile:

2 Likes