Using Expo Libraries on Horizon OS: A Guide to Compatibility

Authors
Jan Jaworski
Software Engineer
@
Callstack
No items found.

Hello, there!

This is the third blog post in a series covering React Native development for Meta Quest. The goal is to cover all important topics that will allow you to utilize your knowledge on a different platform. This way, you won’t run into unexpected hurdles and can stay productive to provide great experiences for your users.

Read other articles in the React Native for Meta Quest series:

We’ve already highlighted the starting flow for scaffolding a new app using Expo. As mentioned there, there are a few edge cases that we need to take into account when building React Native apps for Meta Quest, such as adjusted Expo project settings, testing on a Quest device, or an (upcoming) emulator, and library compatibility differences.

The good news is that most libraries you know and love will work out of the box. That said, there are a few important differences that you should consider avoiding problems when building your app. Let’s go over the details and look into some examples of what works, what needs additional setup, and what won’t work.

The React Native ecosystem is really big, so to keep things manageable, we’ll focus on libraries provided by Expo; the full list is available here.

Why compatibility isn't 1:1

Meta Quest runs on Meta Horizon OS, a customized version of Android built specifically for virtual and mixed reality experiences. It uses the same AOSP (Android Open Source Project) foundation but has been adapted for experiences in VR. Meta also added its own set of APIs and system services to support VR input, rendering, and performance management.

Because of these differences, there are a few areas where the standard Android assumptions don’t apply. Meta Horizon OS doesn’t include Google Play Services, so libraries depending on them, like Google Maps or Firebase, won’t work. The platform also uses a modified set of permissions, so certain Android permissions or features are restricted or replaced with VR-specific equivalents.

What works

Having said that, most things that don’t fall into the categories mentioned above should just work. This means that you can use core Expo libraries such as expo-file-system, expo-asset, or expo-sqlite out of the box. You can build gallery browsers, collaborative whiteboards, or media control panels without hitting compatibility issues. Even more complex experiences that rely heavily on state management, networking, or animations are fully supported.

In short, if a library is self-contained and doesn’t depend on external services or restricted hardware, it should work on Meta Horizon OS. This makes Expo a great choice for starting VR or mixed-reality projects quickly, while keeping the same workflow you’re used to from mobile development.

What needs work

Expo projects are configured for mobile Android by default. Meta Quest has a few project requirements that you need to change to build and release your app to the Meta Horizon Store. You could do it manually, but Software Mansion prepared an expo-horizon-core plugin that does all the necessary steps for you. The article provides more details and explains how to add it to your project.

expo-horizon-core will help you remove and skip forbidden properties, configure Android product flavors, specify Meta Horizon App ID, and provide Meta Quest-specific JS utilities. Make sure you have it installed and configured before you develop other features for your app.

Once your project is configured, you're ready to build most features. However, certain libraries that depend on Google Play Services or other unsupported Android APIs won't work out of the box. In such cases, you'll need Quest-compatible alternatives. Fortunately, several popular libraries already have solutions available. Let's look at three common examples: in-app purchases, notifications, and location services.

expo-iap

Unlike standard Android, which uses Google Play Billing, Meta Quest has its own billing infrastructure: the Meta Horizon Billing SDK. This platform difference means you need a library that supports the Meta-provided SDK.

The expo-iap library has recently been updated to support Meta Horizon OS, making the integration of payments in your app much easier. It provides a single, cross-platform API for handling in-app purchases. To get started, follow the expo-iap guide and pay close attention to the Meta Horizon OS-specific setup instructions.

Integration with payment solutions will allow you to offer users additional features. Depending on what type of application you’re building, here are some ideas on what you can use it for:

  • Unlocking premium content like advanced lessons, exclusive experiences, or additional app sections.
  • Selling customization options such as avatars, themes, or personalized environments.
  • Offering subscription access to regularly updated content, cloud features, or ad-free experiences.
  • Providing virtual items like in-game currency, creative assets, or tool upgrades.
  • Enabling one-time purchases for full app unlock, export features, or advanced capabilities.

expo-horizon-notifications

If you want to use notifications, you'll need to switch to expo-horizon-notifications, a Quest-compatible fork of expo-notifications. The APIs are identical, and both libraries are maintained in sync, so migration is straightforward. Just update your imports; everything else in your code stays the same.

Note that Expo Push Service is not supported on Meta Quest. For complete API documentation, refer to the expo-notifications docs.

Here’s a short example of how you can use notifications on Meta Quest:

// import notifications package
import * as Notifications from 'expo-horizon-notifications';

// setup notifications settings
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldPlaySound: false,
    shouldSetBadge: false,
    shouldShowBanner: true,
    shouldShowList: true,
  }),
});

// trigger notification by calling method somewhere in your application
Notifications.scheduleNotificationAsync({
  content: {
    title: 'Notification!',
    body: "It work on Meta Horizon OS!",
  },
  trigger: null,
});

Here’s how it should look when you run it on your Meta Quest:

expo-horizon-location

For location services, use expo-horizon-location as a drop-in replacement. Like the notifications library, it maintains the same API, so you only need to update your import.

However, there's an important difference to be aware of: Meta Quest devices don't have GPS hardware. Location is determined through WiFi networks and IP geolocation, which provides city or region-level accuracy at best. This makes it suitable for use cases like:

  • Determining user timezone for scheduling features.
  • Showing region-appropriate content or language defaults.
  • Analytics about user distribution by location.
  • Approximate location for social features, e.g., users in the same city.

Here’s a short example of how you can use location on Meta Quest:

// import location package
import * as Location from "expo-horizon-location";

// request location permission and get current position
async function getCurrentLocation() {
  let { status } = await Location.requestForegroundPermissionsAsync();
  if (status !== "granted") {
    setErrorMsg("Permission to access location was denied");
    return;
  }

  let location = await Location.getCurrentPositionAsync();
  return location;
}
Access location on Meta Quest
Access location on Meta Quest

There are other important considerations that are worth keeping in mind, but should not be blockers, such as design guidelines, which are different from what you might be used to on mobile. Hit targets, navigation, and typography also need refinement, e.g., if you want to use a popular component library, you might need to make adjustments to accommodate your app for VR.

If you want to write cross-platform code for Meta Quest and other devices, you might need to use the isHorizonDevice() method from expo-horizon-core to guard against executing platform-specific logic on platforms that do not support it.

Other libraries, like expo-sms or expo-sensors, provide feature-specific checks that should be used to avoid executing unsupported logic.

What doesn’t work

Let’s review a few examples of things not supported on Meta Quest. It’s by no means comprehensive, but it should give you a good idea of what to look out for and how to handle such cases.

When developing for Meta Horizon OS, you need to pay attention to:

  • Mobile-specific hardware & APIs: Cellular (SMS & Calling), GPS
  • Libraries and dependencies using Google Play Services (GPS): Google Authentication, Notifications, Billing
  • Prohibited and unsupported permissions from Android: Dangerous (e.g., INSTALL_PACKAGES), or irrelevant for VR devices (e.g., CALL_PHONE)

They are not supported, and you’ll have to find alternatives.

If you set up your project using expo-horizon-core, things like prohibited permissions will be disabled.

Summary

You’re one step closer to utilizing the full potential of React Native and Expo without running into unexpected issues. Having read this article, you’ll know how to navigate the Meta Quest ecosystem and what to do to reach out for an alternative solution.

In the near future, we will cover how to prepare your app for release to the Meta Horizon Store, so stay tuned!

Table of contents
Exploring VR with React Native?

We can help you build immersive VR apps powered by React Native frameworks.

Let’s chat

//

//
Insights

Learn more about

Virtual Reality

Here's everything we published recently on this topic.

Sort
No items found.
No items found.
//
Virtual Reality

We can help you move
it forward!

At Callstack, we work with companies big and small, pushing React Native everyday.

VR App Development

Build low-latency streaming apps that work across all leading platforms with maximum performance.

React Native Development

Hire expert React Native engineers to build, scale, or improve your app, from day one to production.