expo: Regression in support for react-native-get-random-values
Summary
react-native-get-random-values uses NativeModules.ExpoRandom.getRandomBase64String(byteLength)
to polyfill crypto.getRandomValues()
in Expo Go:
In converting expo-random
to use JSI, we break this polyfill. We should fix this because it is documented in the extremely popular uuid
package.
Managed or bare workflow? If you have ios/
or android/
directories in your project, the answer is bare!
managed
What platform(s) does this occur on?
iOS
SDK Version (managed workflow only)
45
Environment
expo-env-info 1.0.3 environment info:
System:
OS: macOS 12.2.1
Shell: 5.8 - /bin/zsh
Binaries:
Node: 16.13.0 - ~/.nvm/versions/node/v16.13.0/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 8.1.0 - ~/.nvm/versions/node/v16.13.0/bin/npm
Watchman: 2022.01.24.00 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.11.2 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 21.4, iOS 15.4, macOS 12.3, tvOS 15.4, watchOS 8.5
Android SDK:
Android NDK: 21.0.6113669
IDEs:
Android Studio: 4.1 AI-201.8743.12.41.7042882
Xcode: 13.3.1/13E500a - /usr/bin/xcodebuild
npmPackages:
expo: ~45.0.0-beta.9 => 45.0.0-beta.9
react: 17.0.2 => 17.0.2
react-dom: 17.0.2 => 17.0.2
react-native: 0.68.1 => 0.68.1
react-native-web: 0.17.1 => 0.17.1
npmGlobalPackages:
eas-cli: 0.50.0
expo-cli: 5.4.2
Expo Workflow: managed
Reproducible demo
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 44 (25 by maintainers)
Hello! Could it be that this was re-introduced as a regression in SDK48 on Android?
I’m seeing
undefined is not a function
pointing to the line:coming from getRandomValues -> getRandomBase64
I have tried:
expo-random
andreact-native-get-random-values
With no luck. Am I forgetting something? Thank you!
As a workaround, I made a polyfill considering that
expo-standard-web-crypto
depends onexpo-random
which is now deprecated in Expo SDK v48.Here is my code based on the
expo-standard-web-crypto
shim:Here’s the current state of this issue for anyone searching for resolutions:
react-native-get-random-values
package has been migrated to usingexpo-random
so it should not error, but it will throw deprecation warnings.Error: Native module not found
issue is unexpected at this point and might indicate you need to updatereact-native-get-random-values
.expo-crypto
and use thegetRandomValues
function from it – it closely matches the Web APIwindow.crypto.getRandomValues
, you can useexpo-standard-web-crypto
or thecrypto-shim.js
file posted above. You need to make sure it’s run or imported in the top of the App.ts file.Note: you can work around this right now by using
expo-standard-web-crypto
instead ofreact-native-get-random-values
:@tsapeta I don’t know if you have read #7209, but there is some more background in there.
Usually when people are using
react-native-get-random-values
it’s because they are using some package which weren’t made specifically for React Native/Expo, and depend on the globalcrypto.getRandomValues
to be available. This is available in the browsers, Deno, Node.js, etc.I’ve been trying for more than four years (https://github.com/facebook/react-native/pull/20686, #7209 😅) to get this into React Native or Expo so that all of these packages would just work. And if this is something that is of interest to Expo I would be very happy to submit a PR for this. @brentvatne also took a stab at it here #9716, so maybe you have some input?
Having
crypto.getRandomValues
just work out-of-the-box without any setup for the user would be such a great benefit to the ecosystem, sinceMath.random()
shouldn’t be used for anything important, and all other javascript environments have moved over tocrypto.getRandomValues
.react-native-get-random-values
only polyfills iftypeof global.crypto.getRandomValues !== 'function'
, so if e.g. SDK 49 would get support for it there wouldn’t be any conflicts for people already using it.That being said, the part of the code that maintains different Expo SDK versions is here:
https://github.com/LinusU/react-native-get-random-values/blob/0a48c10a395c19affb9e24044a31e6e56afbf20a/index.js#L30-L34
So maybe we just need to add something new for SDK 48 support? Maybe
global.ExpoModules.ExpoCrypto
instead ofglobal.ExpoModules.ExpoRandom
?edit: Just saw that you were the last one to edit those lines so you’re probably quite familiar with it 😅 I mostly tried to answer the “Maybe you could use them directly without
react-native-get-random-values
?” and then spun onAfter trying all the above recommendations, nothing worked for my case
The only thing that FINALLY worked is merging the global.crypto with ‘expo-crypto’ in the polyfills
// polyfills.js
@aleqsio My usecase falls under the 3rd category you mentioned:
I’m trying to create my own polyfill
crypto-shim.js
but the issue is that the 3rd party package import always runs before mycrypto-shim.js
. I’m on Expo SDK 49 using the newapp/
based expo-router so I don’t have aApp.ts
file.3rd party package:
The
in 3rd party
line always gets logged before any of my shims, no matter where I place it. Where can I run my polyfills so that they’re actually polyfilled in time for the imports?If I edit
node_modules/expo-router/entry.js
, then it finally polyfills before the import. Is there a way I can insert my polyfills intonode_modules/expo-router/entry.js
?EDIT: solved by changing the
"main": "index.js",
inpackage.json
then doing the polyfill code in there.index.js:
I am trying to upgrade to expo 48, but new builds in expo go fail with
We are using
uuid
andreact-native-get-random-values
in version 1.8.0, which is the latest version afaik and it worked until now. With expo 48 it does not throw a deprecation, it throws a hard error, so this is not compatible anymore. I tried usingexpo-standard-web-crypto
, but it does not seem to do anything.I tried this in our
App.tsx
and in ourindex.js
, wherereact-native-get-random-values
was imported, but neither worked. It does not seem to kick in.For context: We have a mono repo setup with a web app, a node api and the mobile app. We also have a utils package where we are using
uuid
. So it is not an explicit dependency of the mobile package. As I stated initially, all of this worked just fine with expo 47 andreact-native-get-random-values
.To clarify, the regression wasn’t introduced by the migration to JSI, but by making
expo-random
an Expo module in general (it was a standard React Native module before). The polyfill assumesexpo-random
is accessible fromNativeModules
object, but now it should also look for it inglobal.ExpoModules
. I’ll make a PR inreact-native-get-random-values
to fix this.Thanks for the PR! This is fixed in the following release of
react-native-get-random-values
:🚢 1.8.0 / 2022-05-02
@Michaelsulistio Thank you so much dude, anyone using expo router, you need to define a custom entrypoint and polyfill from there first. Make sure to clear your cache if it just drops you back to the expo start screen.
@Michaelsulistio this is the perfect solution for using expo router! Thanks!
Since the last message here was only a bit more than a month ago, I’m going to take a chance. I’m in Expo version 48, and was switching from using the old
uuid
+react-native-get-random-values
to instead use only the “Crypto” package from expo directly. I only need to generate random UUIDs, so the:But I kept getting told
The only way to get random UUIDs that I can figure out is to replicate @brentvatne’s solution from the first comment:
Have I missed something to get the Crypto package working correctly in Expo 48?
So, is there any path forward? I just tried upgrading to Expo 48 but I am encountering this issue. It’s b/c of an underlying dependency needs the getRandomValues and I can’t get past the
Error: Native module not found
. I tried the crypto-shim.ts to no avail.I’m growing tired of the Expo approach of both trying to be the default runtime for react native but also saying “not our problem” when they upgrade and break things that have been a part of the ecosystem for years.
I’m afraid it’s not the thing that the JS engine should do. This is one of the Web APIs, which are implemented by the browser not the JS engine itself as they are not part of the language.
I think this is exactly the same case as with the JS engine vs the browser. There are many other APIs that need polyfills in React Native, if we add one then we should add the others as well. I would rather be in favor of not bloating the JS runtime and not adding too much into the core if this is not necessary. That being said, polyfilling it automatically when
expo-crypto
is installed sounds like a good compromise. I’ll add this to our roadmap for SDK 49 😉This is exactly what the new
getRandomValues
does 🙂 Fully native, called through JSI (as every function of a native expo module).Yes, I think we’ll go this way 👍
@peterpme After a quick look, I don’t think it could cause a regression, but we’ll take a look at that.
expo-random
is generally deprecated in SDK 48, we merged it intoexpo-crypto
which now has some new cool features, including its owngetRandomValues
andrandomUUID
functions. Maybe you could use them directly withoutreact-native-get-random-values
?Not sure what was up with it but
yarn cache clean
and following CONTRIBUTING.md again seems to have sorted it.@ramiel1999 - it is a good solution, i’d recommend it