Size is easy to measure. This script splits an APK into compiled code (dex), native libraries (lib), the web app and everything else, using the bytes each entry occupies inside the file:
import os, sys, zipfile
def part(name):
if name.endswith('.dex'):
return 'dex'
if name.startswith('lib/'):
return 'lib'
if name.startswith(('assets/public/', 'assets/www/')):
return 'web'
return 'other'
print(f"{'APK':<22}{'total':>7}{'dex':>7}{'lib':>7}{'web':>7}{'other':>7} (MB)")
for label, path in zip(sys.argv[1::2], sys.argv[2::2]):
sizes = dict.fromkeys(['dex', 'lib', 'web', 'other'], 0)
for entry in zipfile.ZipFile(path).infolist():
sizes[part(entry.filename)] += entry.compress_size # bytes stored in the APK
mb = [os.path.getsize(path)] + list(sizes.values())
print(f"{label:<22}" + ''.join(f'{n / 1e6:7.2f}' for n in mb))Run on release builds of the Cordova 129 starter of Gradle, a minimal Capacitor 243,123 app (a Vite 25,978 page plus Preferences, as in Creating an App-Native Projects as Source) and BookNest (Signed App Bundle):
APK total dex lib web other (MB) Cordova starter 2.76 2.16 0.00 0.04 0.50 Capacitor starter 3.16 2.48 0.00 0.01 0.63 Capacitor BookNest 18.38 7.17 7.80 0.99 2.11
An empty WebView app costs about 3 MB, almost all of it the AndroidX 234 and bridge code in dex, because the engine is the system's. BookNest's growth comes from its plugins, not from Capacitor: SQLCipher 566,000 's native libraries for four ABIs make up the lib column, and its web app is under 1 MB. React Native 36,878 starts higher, because it ships an engine: in a release build of React Native's BookNest (Expo SDK 57 6,418 ), libreactnative.so (7.1 MB) and libhermesvm.so (2.6 MB) plus the C++ runtime add about 11 MB for each ABI before any app code. A Flutter 16,720 APK likewise carries libflutter.so and your compiled Dart per ABI, and a Tauri 126,184 APK carries your Rust core per ABI. App bundles (Signed App Bundle) shrink what users download to one ABI in every case.
Runtime speed follows the architecture. A WebView app's frames are as smooth as the web page inside it, and each plugin call pays an asynchronous JSON round trip, harmless for a camera but costly in a loop of thousands of calls. React Native's JSI removes the serialization for such calls, and Flutter avoids the platform's view system entirely, which helps heavy animation and custom drawing. For forms, lists and content screens, the pattern of most business apps, users will not tell the three apart; profile before you blame the framework.