No, this is NOT (necessarily) safe. The other answers are mostly correct, except they are making two (common, but incorrect) assumptions: that localhost is always 127.0.0.1, and that a webserver running on your machine is one you wanted to run. THESE ARE NOT SAFE ASSUMPTIONS.
Some machines, due to either deliberate modification for some purpose or simply because the HOSTS file is minimal (or missing), do not define localhost as 127.0.0.1 (or ::1 for IPv6) and therefore do a DNS lookup for that name. DNS is of course generally not secure; an attacker on the same network (or anywhere between you and a DNS server willing to authoritatively state what IP address "localhost" maps to) can inject a DNS reply specifying their own IP address. Your app then loads the web content from the attacker's web server. The attacker can send the victim malicious web content that steals the creds to your service, steals content from your account, maliciously misuses your account, uses JS-to-native API bridges to attack your device (or at least maliciously access the data the mobile app can see), and so on.
OK, so what if you used "127.0.0.1" instead of "localhost"? IP addresses never need to go over DNS, 127.0.0.1 is always routed just to your own machine, and you should be fine, right?
Still a bad idea! TCP sockets do not respect privilege isolation between users (or between sandboxed apps). If your mobile user has one sketchy app that is running a webserver on that port, your app will connect to the malicious server instead of to the one your app tried to launch (which will have failed to bind the socket, as it's already in use). You could almost certainly get that into the app store, too; it's not using any disallowed APIs or anything, just serving web content on a loopback socket bound to a particular port (same as you are). Similarly on servers/desktops/laptops, if your machine allows non-admins to remote in (via SSH, remote desktop, etc.) then one of those users could spin up a malicious web server on the port you use, and wait for your app to connect to it.
Of course, even without any malicious attempt, this whole idea is just fragile. As I mentioned above, there's no guarantee that no other process is running a web server on the same port you've chosen. There's only 2^16 of them to choose from, and for some ranges the OS itself may randomly bind outbound connections to that port so it could be in use by a client app (like a web browser) rather than a server. Either way, the server used to offer up your web content will fail to bind the port, your app won't be able to talk to the server it expects, and your user will have a bad experience.
Note that this has nothing to do with CORS. WHATEVER origin you load the content from, your server will need to allow that origin to see web responses.
The important point is to ensure that the web content is loaded securely, and HTTP over normal TCP - that is, without TLS or other ways to authenticate and protect the connection - is not secure!
Solution: just load the content (via HTTPS) from your Internet-facing web servers. Then your app doesn't need to load anything over HTTP, your web service doesn't need to allow any requests from any web page loaded over HTTP, and the app can be sure it's loading content from the right server.
You can even serve the content from the same domain, so that cross-origin (that is, CORS) requests aren't even needed! Just use old-school XMLHttpRequests (or Fetch, without CORS) and rip out anything CORS-related from the web service.
The previous company I worked for had a product that did something like what you're describing - loading data from a localhost web server into a webview - and we ran into a really funny problem where some people were reporting that the web view was just... empty. No content. The local server was running, the content was packaged and installed correctly, the webview was trying to make the web requests... but it seemed like the server wasn't responding. Long story short, we eventually tracked it down to "localhost" being undefined on those machines. This was only a few users out of ~10,000 (on Macs, as that was the only platform that ran our app), but it was enough of a problem that we stopped using "localhost". Of course, "127.0.0.1" turned out not to be secure either, as I explain above, but that decision was made before they had a security person on the team.