Ordering an iFood from your car

How we developed the iFood app for VW cars

Larissa Yasin
iFood Engineering

--

2020 was a different year for all of us, unless you are living in an isolated island, you know what I'm talking about. And, besides everything that was going on in the world, we received a challenge:

What if I'm coming back from work and I want to order my food, for when I arrive, it will be almost the time to be delivered?

Volkswagen contacted us in the beginning of 2020 and they said how great it would be to order from iFood in the car without the phone — here in Brazil is against the law to use it while driving. They were starting to release some cars in Brazil with VW Play (VW Play is an Android Automotive OS) so they ask us to do a version for iFood.

Here is where our journey begins…

We decided to reuse everything that we could from the Android app. So we only created one new service to login. The features of the app are:

  • Select registered addresses
  • Add a new debit/credit card
  • Re-order

Pretty simple right? Well…. it wasn't!

What is different from developing an Android app for a smartphone and for a car?

Since VW Play is an Android system, we were developing an Android app but we had to be careful about the layout.

Adding card

We needed big buttons, short texts, be aware that the keyboard was going to use a large space in the screen.

Basically, it was the opposite from our current app.

Also, we had to question ourselves constantly: is this going to distract the driver?

Setting up the payment in the car

When you need to add a credit card in any app, it is not a fun thing to do. You need to get your card from your wallet, type a lot of numbers, check the back of the card and input more information. So how someone is going to add their card while driving?

Payment screen

Our solution was: only allow to input the card when the car is not in movement. You might be thinking: hey, just use google maps or something…

The thing is the system doesn't support Google Play services or contains any kind of maps already installed. There was only access to the GPS so
we used Android's Location getSpeed() property to block the card input.

Keep it clear and direct

Thinking about not distracting the driver, we had to approach our way to communicate differently. If you ever ordered from iFood, you know that the screen that shows your delivery estimation time, status (if the restaurant is preparing, the driver already picked it up) and some details about the order has a lot of information, which is great! But in a car, that is too distracting.

In the VW Play docs, they say that we should have a 200 character limit for each screen. So, instead of getting all those information, we just inform the driver that the order was made it.

Status screen

A new way to login

The only time you will need to get your phone to order from iFood is to login. We thought reusing the e-mail/password or send a token to the user but how long was it going to take just to log in?

Login screen

So we created a new authentication method that "connects" the iFood account to the app by reading a QR Code. The QR Code reader is inside the iFood app, so it takes like 5 seconds to get there and scan it. Way faster then typing your e-mail and your password!

Going deep into the code

So we talked about reusing some things about the Android app, and I'm going to explain a little bit how that works.

How was the app architecture structured?

Thinking about reusing the API's and business logic for the car app, we decided to use the same code repository as the Android app. So now we have this big monorepo with a lot of code that we are not going to need.

We spent a lot of time discussing how our architecture was going to be, but in the end we decided to create a new app inside the code repository called :car-app and to reuse the features that the :app was importing. So our ideal architecture was like this:

ideal architecture

The thing is that our :core and :app have a lot o legacy code back from when everything was one big module. So to import some modules like :address, there were some dependencies inside the :app .

current architecture

The solution was to import some unnecessary code to the :car-app since we had a deadline and then start slowly to fix those dependencies.

Use Cases, Repository…

Here in iFood we use the CLEAN architecture, so we have Use Cases with the business logic. So we tried our best to just inject the Use Case in our ViewModel, and if some business logic changed, it was going to reflect in the :car-app. We wanted that because the app should have the same rules as the :app. For example, the :app changed how some information was being saved to be even safer, but since in the :car-app we were calling that Use Case, we just needed to update the code so it could work fine.

Some Use Cases had a lot of business logic that we didn't need or we didn't have the same information that the :app has, so we created our own Use Cases, injecting the :app repository classes. This way we could access the same API's and local cache logic as the :app.

Now what?

Now you can make a reorder to your home when you are coming back from work! (If you have a car with VW Play of course)

We have some plans for the future:

  • Add voice integration (How cool it would be to just say: "Hey car, I want to order a Big Mac from Mc Donald's to my home")
  • Make a new order! Select a new restaurant, a new dish…

I hope you drive safely and with food waiting for you at home!

--

--