While I agree with the other answers, I find there are a few pragmatic things that are overlooked there.
Full disclosure: I work for a company that builds obfuscation / protection software for mobile applications.
Full, unbreakable protection is not possible for an app running on an attacker-controlled device. However, software exists that aims to raise the bar and makes it less / not worthwhile for a person to carry out an attack.
Typically these solutions cover two aspects
Static protection
This usually includes a bunch of obfuscation techniques aiming to make it difficult for an attacker that wants to analyse a mobile application by looking into the binaries using tools like IDA Pro, Ghidra and Hopper.
Techniques here are control-flow obfuscation, semantic obfuscation (class, method, ... names), arithmetic obfuscation, string encryption, class encryption, ...
These make it very difficult to "peek" inside a binary and figure out what is going on, but don't offer a lot of protection when an attacker looks at the application while it is running on the device itself.
Dynamic protection
These are protection techniques aim to shield an application from analysis or modification while it runs on the device. Popular tools here are debuggers (lldb, gdb, ...) and hooking frameworks (Frida, Cydia Substrate, ...).
Techniques here will try to block / detect the use of these tools, detect tampered execution environments (jailbroken / rooted device, emulators), modifications made to the application and much more.
Conclusion
While it's of the utmost importance to ensure your application was built using the well-defined security practices (obfuscation / protection software will not help you here!), tools exist that can function as a bunch of shells around your application that all together make it much more difficult, and hopefully not worthwhile, to crack your application.