Most of these limitations are no longer true.
First of all, you didn't mention that Expo had 2 workflows - Bare and Managed. You are talking about Managed Workflow here. "Bare Workflow" is very similar to RN CLI, it allows using custom native code, but also gives possibility to use Expo SDK libraries
- Handling native code:
First - there was a bare workflow which allowed that, in some cases you could still use Expo Go.
Second - Since SDK 41/42 using custom native libraries (including Bluetooth) is possible in Managed Workflow too, thanks to "config plugins" and "custom development clients".
- Ejecting is one-way and buggy: The eject process has been greatly improved recently and it should work almost perfectly. Why? Because every time you use EAS Build (expo new cloud build service), or "expo run" command on Managed project, it is ejected each time before it is built. So Expo uses ejecting in its own building workflow! The thing is that "eject" is named "prebuild" there, but it's the exact same thing.