Amazon Developer

as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
Ring
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support
Native
Skip to main content
OmniKit is a specification, a toolchain, and a runtime. It defines an interface definition language (IDL). It supplies the compiler that projects an IDL package into a given programming language. It provides the runtime that resolves a component by id and returns the interfaces that component implements. It also sets the rules that keep those binary interfaces stable as implementations change. The Vega native interfaces are built with OmniKit. Amazon uses it to publish system capabilities such as audio, graphics, media playback, Bluetooth, and networking as OmniKit components. Your app consumes them. You resolve a component by its id at runtime, then ask it for the interfaces you need. The SDK ships the IDL files that declare those interfaces, along with the tools that turn them into C++. Your build generates the C++ bindings and headers from the IDL, compiles them into a library, and links that library into your app. You call the interfaces through those generated bindings. Those contracts are binary-stable. A component your app compiles against keeps working when the implementation behind it changes.

How your app consumes a component

Amazon publishes each native capability as a component carrying a component id, a unique string in reverse domain notation. The API Reference documents them, for example com.amazon.kepler.audio. To use a capability, resolve its component by id, then query that component for the interface you need. You call the interface through its C++ projection, which your build generates from that package’s IDL. That id is the component’s whole identity to your app. Your code doesn’t know where the implementation lives, or whether it lives in a shared object or in-process, and it doesn’t need to.

Why the interfaces stay binary-stable

With an API, software components are combined at the source level. You compile them together to produce executables and shared libraries. A change on the other side means recompiling your own. A stable Application Binary Interface (ABI) works differently. Components compile independently of one another, then combine safely at runtime. This air gapping decouples dependencies from dependents. For your app, the implementation behind an interface can be rebuilt, patched, or replaced without you recompiling. Using a stable ABI, an author can write components in their preferred language, as long as every party communicates through the agreed ABI.

Interfaces, packages, and projections

Every contract has two sides. A provider implements the contract, and a consumer uses it. OmniKit’s tools serve both sides from the same source. Contracts are authored as language-neutral interfaces in an interface definition language (IDL). An interface describes the behavior of a component, never its implementation. Related interfaces live together in packages. For each supported language, the IDL compiler reads a package and generates a language projection: the API you program against in that language. For interfaces, their generated projections do the crossing. They adapt your language’s calling convention to the stable C ABI that the two sides meet at, through that language’s foreign function interface (FFI). The result presents the contract as a natural API, so each party works in the style of its own language. For native Vega apps, the compiler generates C++ bindings and headers, and your build compiles them into a library your app links against. Every language projection implements the same ABI, a C ABI vtable. Binaries compiled from different languages therefore interoperate, so a C++ app can call a component implemented in another language. Neither side takes a compile-time dependency on the other. Diagram that shows the IDL compiler turning one IDL package into language projections for a consumer and a provider. Consumer code calls its own projection, crosses the stable C ABI vtable by FFI, and reaches the provider's projection and implementation. Each party interacts only with its own projections, so the two sides meet at the ABI rather than in source. The languages in the diagram are illustrative. Either side could be written in any supported language.

Example: one contract, three independent parties

This example has three parties: two device vendors that provide components, and your app, which consumes one or both. The first vendor provides a Wi-Fi device implementation. The vendor authors an IDL describing the behavior of a generic device, generates a language projection, and implements a component with the id com.example.wifi. The vendor then publishes the component binary, the component id, and the IDL. Your app needs that Wi-Fi device. Take the published IDL and generate your own language projection. Ship the vendor’s component binary alongside your app, then load the component at runtime by id. A second vendor ships a competing Wi-Fi device. That vendor reuses the IDL the first vendor already published, then publishes its own component binary under the id com.othercompany.wifi. To widen device support for your customers, add the second component id as another device and patch your app. None of the three parties coordinate beyond publishing binaries that conform to the same IDL contract. In the Vega native interfaces, Amazon is the vendor and your app is the consumer.

How interfaces change over time

A published IDL package doesn’t change. Its name, path, and contents all feed the structural hashes of the types inside it, so editing any of them produces a different contract. Existing binaries would stop interoperating with it. Interfaces grow by addition instead. When a capability needs a new method, Amazon publishes a new interface that extends the existing one, with a version number appended to its name. IAudioEffect is followed by IAudioEffect2 through IAudioEffect6, and IDisplayListener by IDisplayListener2 and later versions. For your app, this means two things. Code written against an existing interface keeps working, because that interface is never edited. To reach newer capability, query the component for the newer interface, as described in How your app consumes a component.

Terminology

The following terms don’t map one to one onto each other. Read each one for what it excludes as well as what it covers.

Interface

A language-neutral behavioral contract between consumers and providers. It isn’t a tangible thing that gets instantiated. It’s the IDL-side counterpart to a component implementation on the projection side. Interfaces only describe behavior. They don’t prescribe how that behavior is implemented. One component can implement several interfaces drawn from several packages, and one interface can be implemented by several components.

IDL package

A file holding one or more interfaces, read by the IDL compiler to generate a projection for a given language. A package isn’t a description of a component, and it doesn’t exist outside the domain of the IDL compiler. Packages group related types under a common identity. That identity is immutable and forms part of the structural hashes of the types inside. The package identity becomes the namespace for the generated types, but has no tangible form in the projection layer.

Language projection

The mapping of an IDL package’s contents onto the actual code of a programming language, and the API you program against in that language. A projection adapts that language’s calling convention to the stable C ABI, so it’s what does the crossing at a call. In C++ the compiler emits it as generated bindings and headers. A projection isn’t the language components are written in, and it isn’t a common language shared between consumers and providers. Projections are private to each party of a contract. Implementing a component in C++ doesn’t mean consumers must consume it in C++.

Component

An implementation of one or more interfaces drawn from one or more packages, identified by a unique string. Consumers request a component by id, then query it for the interfaces they need. A component isn’t the implementation of a single interface or a single package. Any one-to-one relationship between a component and an interface or package is a choice, not a requirement.

Component id

The unique string identifier for a component, following the reverse domain convention. It’s the link between the consumers and the provider of a component. A component id isn’t a string representation of the component name, the IDL packages implemented, or the interfaces implemented. An id can be anything, provided it’s unique. Any resemblance to a component, interface, or package name is a choice.
Last modified on October 29, 2026