はじめに
React Native(Expo)でcrypto.randomUUID()を使ってUUIDを生成しようとしたところ、Webでは動くのにアプリ(iOS/Android)ではProperty 'crypto' doesn't existというエラーが発生しました。
本記事では、このエラーの原因とexpo-cryptoを使った解決方法を紹介します。あわせて「なぜブラウザでは動くのにアプリでは動かないのか」についても整理します。
対象読者:Expo / React NativeでWeb向けのAPIを使ってエラーに遭遇した方
問題
以下のようにUUIDを生成するコードを書きました。
const id = crypto.randomUUID();
Expoアプリで実行すると、次のエラーが発生します。
ReferenceError: Property 'crypto' doesn't exist
一方、同じコードをWeb(ブラウザ)で実行すると問題なく動作します。
原因
cryptoはnpmパッケージではなく、Web Crypto APIというブラウザが提供するグローバルオブジェクトです。importせずに使えるのは、ブラウザがglobalThis(window)にcryptoを用意しているためです。
JavaScriptで使える機能は、大きく次の3層に分かれます。
| 層 | 例 | 決める人 |
|---|---|---|
| 言語仕様(ECMAScript) |
Array, Promise, JSON
|
TC39 |
| Web API |
fetch, crypto, DOM, localStorage
|
W3C / WHATWG・ブラウザベンダー |
| ライブラリ | axios, uuid | 誰でも(npmで配布) |
React Nativeで使われるJSエンジンHermesが実装しているのは、言語仕様(ECMAScript)のみです。cryptoのようなWeb APIは「ホスト環境」が提供するものであり、ブラウザは提供していますが、React Nativeはcryptoを提供していません。
そのため、アプリ上ではグローバルにcryptoが存在せず、エラーになります。
解決方法
Expoが提供するexpo-cryptoを使います。iOS/Android/Webのすべてで動作します。
1. パッケージのインストール
npx expo install expo-crypto
2. randomUUIDをexpo-cryptoから呼び出す
import * as Crypto from 'expo-crypto';
const id = Crypto.randomUUID();
これでアプリ・Webの両方でUUIDが生成できるようになりました。
おわりに
cryptoはブラウザに組み込まれたWeb APIであり、JSの言語機能そのものではありません。Hermes(JSエンジン)は言語仕様のみを実装しているため、React Nativeではcryptoを利用できませんでした。
「Webで動く=React Nativeでも動く」とは限らないので、グローバルAPIを使う際は、それが言語仕様なのかWeb APIなのかを意識し、MDNの「ブラウザーの互換性」やReact Nativeのドキュメントで提供状況を確認するのがおすすめです。
参考
JISOUのメンバー募集中!
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてください!
▼▼▼
https://projisou.jp
