OpenAIExpoMar 12, 2026, 1:30 PM

The next generation of Expo APIs: MediaLibrary and Contacts

A condensed section focused on the key takeaways first.

Original Post

Quick Digest

Summary

A condensed section focused on the key takeaways first.

openaienmodel: gpt-5-mini-2025-08-07

Expo SDK 55 — MediaLibrary@next and Contacts@next

Key Points

  • shared objects & refs
  • query builder for media
  • patch() + getDetails for contacts

Summary

SDK 55 introduces next-generation Expo APIs for media and contacts via expo-media-library/next and expo-contacts/next. The libraries use Shared Objects & Shared Refs to expose object-oriented proxies to native data (Asset, Album, Contact), offering granular getters, builder-style queries, performant batched reads, and safe partial updates. These changes reduce boilerplate, avoid passing IDs everywhere, and improve TypeScript ergonomics.

Key Points

  • MediaLibrary@next

    • Asset and Album are proxy classes that reference native gallery items.
    • Create assets with await Asset.create(uri) and manage albums via Album.get() / Album.create().
    • Granular getters (e.g., asset.getLocation(), asset.getShape(), asset.getInfo()) avoid fetching full metadata when unnecessary.
    • New Query builder supports predicates (gt, gte, lte, lt, eq, within, album), orderBy, limit, and offset for readable, composable filtering.
  • Contacts@next

    • Contact instances reference system contacts and expose async instance methods; create/fetch/pick via Contact.create(), Contact.getAll(), Contact.presentPicker().
    • Fine-grained operations: contact.addEmail(...), contact.setImage(uri), and getters like contact.getGivenName() for minimal round-trips.
    • getDetails([...fields]) and getAllDetails([...]) return narrowed types (TypeScript warns when accessing unfetched fields).
    • patch() applies partial updates (skips undefined fields) and pairs naturally with getDetails(); update() still replaces the whole contact.
  • Migration & practical notes

    • New packages are published under expo-media-library/next and expo-contacts/next; expect further library migrations in future SDKs.
    • Prioritize switching to granular getters/queries and instance methods to reduce data transfer and avoid ID-management bugs.
    • Check the new docs and open issues/feature requests on GitHub for feedback or migration questions.

Recommended actions for engineers

  • Try expo-media-library/next and expo-contacts/next in a branch; replace heavy metadata calls with granular getters.
  • Adopt Query builder patterns for media filtering and getDetails() + patch() for contact forms to minimize updates and improve performance.
  • Validate TypeScript types after narrowing-based calls to catch missing-field access at compile time.

Full Translation

Translations

A translation section that keeps the flow of the original article.

openaijamodel: gpt-5-mini-2025-08-07

Expo APIの次世代:MediaLibrary と Contacts

Product • 2026年3月12日 • 読了時間: 約5分

Wiktor Smaga • Engineering

SDK 55ではコアライブラリの次世代が導入されます。Shared Objects & Shared Refs により、これらのライブラリでネイティブデータとやり取りする方法が根本的に変わります。Shared Objects と Shared Refs は、モジュール間の不要な結合を避けつつより深い統合を実現するため、Expoライブラリの将来だと考えています。Shared Objects と Shared Refs の詳細はこの記事を参照してください。

SDK 54では File System を新しいオブジェクト指向APIで更新しました。今回は Contacts と MediaLibrary のアップグレードです。更新されたライブラリは expo-contacts/next と expo-media-library/next として利用可能になっています。今後の SDK リリースでも他のライブラリへこれらの機能を順次導入していきます。

以下では contacts と media library パッケージで何が変わったかを見ていきます。

MediaLibrary@Next

コアコンセプト

新しい API はシンプルな考えに基づいています: Album と Asset はネイティブデータのプロキシとして動作するクラスになりました。これらはシステムギャラリー内のオブジェクトへの参照を保持し、メタデータを簡単に取得できます。新しいアセットを作成するには、ローカルURIを静的関数 Asset.create() に渡す必要があります。このコマンドはファイルをギャラリーに追加し、Shared Object を返します。

// Create an asset from a local URI
const asset = await Asset.create('file:///path/to/photo.png');

アセットを取得したら、管理はずっと直感的になります:

// Fetch an album and add the asset directly
const album = await Album.get('Holiday 2026');
await album.add(asset);

// Or create a new album and add the asset in one go
const album = await Album.create('Holiday 2026', [asset]);

プロパティへの直接アクセス

旧APIでのボトルネックは、getAssetInfoAsync() が返す巨大なオブジェクトのサイズでした。位置情報を確認するだけでも全プロパティを含む巨大なプレーンオブジェクトを取得しなければなりませんでした。MediaLibrary@Next は粒度の細かいゲッターを提供し、必要なものだけにアクセスできます。画像の寸法を確認するために全メタデータを取得する必要はもうありません。

await asset.getLocation(); // { longitude: 50, latitude: 20 }
await asset.getShape(); // { width: 100, height: 100 }
// すべて必要ですか?まだ可能です:
await asset.getInfo();

強力なクエリ

MediaLibrary@Next はメディアをフィルタリングする新しい方法を導入します。新しい Query クラスはビルダーパターンを採用しており、可読性の高い方法でより具体的なクエリを作成できます。サポートされる述語は以下の通りです: gt, gte, lte, lt, eq, within, album。また並び替え用の orderBy とページネーション用の limit / offset もサポートします。

const assets = await new Query()
  .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)
  .lte(AssetField.HEIGHT, 1080)
  .within(AssetField.WIDTH, [920, 960, 1080])
  .orderBy(AssetField.CREATION_TIME)
  .limit(20)
  .offset(10)
  .exe();

Contacts@Next

コアコンセプト

Contacts@Next の新しい API は以下の前提で設計されています: Contact オブジェクトはシステム連絡先への参照を保持し、基になるシステム連絡先の状態を取得・更新する多くの非同期関数を持ちます。旧APIとは異なり、毎回手動で ID を渡す必要はなく、特定の Contact インスタンス上で呼ばれる update 関数だけを頼れば、よくあるミスを避けられます。

開始するには、静的メソッドで連絡先を作成、取得、またはピッカーで選択できます:

// Create a new contact
const contact = await Contact.create({
  givenName: 'Andrew',
  familyName: 'Jones',
  phones: [
    { label: 'mobile', number: '+12123456789' },
  ],
});

// Fetch existing contact
const [contact] = await Contact.getAll({ limit: 1 });

// Or pick one using the system UI
const contact = await Contact.presentPicker();

粒度の細かい更新

単一のプロパティを更新するために巨大なJavaScriptオブジェクトを扱うのは誰も好きではありません。例えば旧APIで新しいメールアドレスを追加するには、オブジェクト全体を修正して送り返す必要がありました:

// THE OLD WAY
const updatedContact = {
  ...contact,
  emails: [
    ...(contact.emails || []),
    { address: 'contacts-next@expo.dev', label: 'work' }
  ],
};
await Contacts.updateContactAsync(updatedContact);

今では同じ操作を一行で行えます:

// THE NEW WAY
await contact.addEmail({ address: 'contacts-next@expo.dev', label: 'work' });

すべての連絡先プロパティに対して同様の操作が可能です。プロフィール画像を設定する例:

const result = await ImagePicker.launchImageLibraryAsync();
await contact.setImage(result.assets[0].uri);

高パフォーマンスなクエリ

特定のフィールドだけを取得したい場合、粒度の細かいゲッターが使えます:

const givenName = await contact.getGivenName();

複数のプロパティを取得するには getDetails を使います。興味のあるフィールドの配列を渡してください:

await contact.getDetails([ContactField.EMAILS, ContactField.FULL_NAME]);

連絡先の一覧を構築する場合は、より効率的な関数 getAllDetails() があります。内部では単一のシステムAPIコールを使用するため非常に高性能です。オプションのパラメータとして異なる種類のフィルタリングもサポートします。

// This is a static module function.
await Contact.getAllDetails([ContactField.EMAILS, ContactField.FULL_NAME]);

さらに、これらの関数が返すオブジェクトは引数で要求したフィールドに基づいて狭められた型になっています。TypeScript は取得していないフィールドにアクセスしようとすると警告を出します。

const details = await contact.getDetails([ContactField.GIVEN_NAME]);
console.log(details.givenName); // ✅ "John"
console.log(details.phones); // ❌ TypeScript will show a warning.

patch() + getDetails() の組み合わせ

新バージョンには HTTP の patch に似た patch() メソッドが含まれており、部分的な変更を適用します。undefined のプロパティはスキップされるため、変更したいフィールドだけを更新できます。getDetails() と組み合わせて設計されており、getDetails() が要求されたフィールドのみを取得し、patch() が定義されたフィールドのみを更新します。フォームで一つか二つのフィールドだけを変えるようなケースに最適です:

const details = await contact.getDetails([ContactField.EMAILS, ContactField.GIVEN_NAME]);
details.givenName = 'John';
await contact.patch(details); // システム上の givenName のみが更新される。

連絡先プロパティを完全に置き換えたい場合は、update メソッドを使うこともできます。patch と異なり、update は連絡先を丸ごと上書きします:

await contact.update({
  givenName: 'New Name',
  familyName: 'New Surname',
  // 他のフィールドはクリアされます
});

新しいドキュメントを確認してください

これらはライブラリの次の反復版であるため、皆さんのフィードバックがこれまで以上に重要です。GitHub issue、機能リクエスト、ツイートなど、どんなフィードバックでも歓迎し感謝します。API の動作例が載った新しいドキュメントもぜひご確認ください!